]> Sergey Matveev's repositories - btrtrc.git/blob - misc.go
Get mmap storage working
[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 type (
25         pieceSum [20]byte
26 )
27
28 func lastChunkSpec(pieceLength, chunkSize pp.Integer) (cs chunkSpec) {
29         cs.Begin = (pieceLength - 1) / chunkSize * chunkSize
30         cs.Length = pieceLength - cs.Begin
31         return
32 }
33
34 type chunkSpec struct {
35         Begin, Length pp.Integer
36 }
37
38 type request struct {
39         Index pp.Integer
40         chunkSpec
41 }
42
43 func newRequest(index, begin, length pp.Integer) request {
44         return request{index, chunkSpec{begin, length}}
45 }
46
47 var (
48         // Requested data not yet available.
49         errDataNotReady = errors.New("data not ready")
50 )
51
52 // The size in bytes of a metadata extension piece.
53 func metadataPieceSize(totalSize int, piece int) int {
54         ret := totalSize - piece*(1<<14)
55         if ret > 1<<14 {
56                 ret = 1 << 14
57         }
58         return ret
59 }
60
61 type superer interface {
62         Super() interface{}
63 }
64
65 // Returns ok if there's a parent, and it's not nil.
66 func super(child interface{}) (parent interface{}, ok bool) {
67         s, ok := child.(superer)
68         if !ok {
69                 return
70         }
71         parent = s.Super()
72         ok = parent != nil
73         return
74 }
75
76 // Return the request that would include the given offset into the torrent data.
77 func torrentOffsetRequest(torrentLength, pieceSize, chunkSize, offset int64) (
78         r request, ok bool) {
79         if offset < 0 || offset >= torrentLength {
80                 return
81         }
82         r.Index = pp.Integer(offset / pieceSize)
83         r.Begin = pp.Integer(offset % pieceSize / chunkSize * chunkSize)
84         r.Length = pp.Integer(chunkSize)
85         pieceLeft := pp.Integer(pieceSize - int64(r.Begin))
86         if r.Length > pieceLeft {
87                 r.Length = pieceLeft
88         }
89         torrentLeft := torrentLength - int64(r.Index)*pieceSize - int64(r.Begin)
90         if int64(r.Length) > torrentLeft {
91                 r.Length = pp.Integer(torrentLeft)
92         }
93         ok = true
94         return
95 }
96
97 func torrentRequestOffset(torrentLength, pieceSize int64, r request) (off int64) {
98         off = int64(r.Index)*pieceSize + int64(r.Begin)
99         if off < 0 || off >= torrentLength {
100                 panic("invalid request")
101         }
102         return
103 }
104
105 func validateInfo(info *metainfo.Info) error {
106         if len(info.Pieces)%20 != 0 {
107                 return errors.New("pieces has invalid length")
108         }
109         if int((info.TotalLength()+info.PieceLength-1)/info.PieceLength) != info.NumPieces() {
110                 return errors.New("piece count and file lengths are at odds")
111         }
112         return nil
113 }
114
115 func chunkIndexSpec(index int, pieceLength, chunkSize pp.Integer) chunkSpec {
116         ret := chunkSpec{pp.Integer(index) * chunkSize, chunkSize}
117         if ret.Begin+ret.Length > pieceLength {
118                 ret.Length = pieceLength - ret.Begin
119         }
120         return ret
121 }