]> Sergey Matveev's repositories - btrtrc.git/blob - misc.go
Switch pieceIndex back to an int
[btrtrc.git] / misc.go
1 package torrent
2
3 import (
4         "errors"
5         "net"
6
7         "github.com/anacrolix/missinggo"
8         "golang.org/x/time/rate"
9
10         "github.com/anacrolix/torrent/metainfo"
11         pp "github.com/anacrolix/torrent/peer_protocol"
12 )
13
14 type chunkSpec struct {
15         Begin, Length pp.Integer
16 }
17
18 type request struct {
19         Index pp.Integer
20         chunkSpec
21 }
22
23 func (r request) ToMsg(mt pp.MessageType) pp.Message {
24         return pp.Message{
25                 Type:   mt,
26                 Index:  r.Index,
27                 Begin:  r.Begin,
28                 Length: r.Length,
29         }
30 }
31
32 func newRequest(index, begin, length pp.Integer) request {
33         return request{index, chunkSpec{begin, length}}
34 }
35
36 func newRequestFromMessage(msg *pp.Message) request {
37         switch msg.Type {
38         case pp.Request, pp.Cancel, pp.Reject:
39                 return newRequest(msg.Index, msg.Begin, msg.Length)
40         case pp.Piece:
41                 return newRequest(msg.Index, msg.Begin, pp.Integer(len(msg.Piece)))
42         default:
43                 panic(msg.Type)
44         }
45 }
46
47 // The size in bytes of a metadata extension piece.
48 func metadataPieceSize(totalSize int, piece int) int {
49         ret := totalSize - piece*(1<<14)
50         if ret > 1<<14 {
51                 ret = 1 << 14
52         }
53         return ret
54 }
55
56 // Return the request that would include the given offset into the torrent data.
57 func torrentOffsetRequest(torrentLength, pieceSize, chunkSize, offset int64) (
58         r request, ok bool) {
59         if offset < 0 || offset >= torrentLength {
60                 return
61         }
62         r.Index = pp.Integer(offset / pieceSize)
63         r.Begin = pp.Integer(offset % pieceSize / chunkSize * chunkSize)
64         r.Length = pp.Integer(chunkSize)
65         pieceLeft := pp.Integer(pieceSize - int64(r.Begin))
66         if r.Length > pieceLeft {
67                 r.Length = pieceLeft
68         }
69         torrentLeft := torrentLength - int64(r.Index)*pieceSize - int64(r.Begin)
70         if int64(r.Length) > torrentLeft {
71                 r.Length = pp.Integer(torrentLeft)
72         }
73         ok = true
74         return
75 }
76
77 func torrentRequestOffset(torrentLength, pieceSize int64, r request) (off int64) {
78         off = int64(r.Index)*pieceSize + int64(r.Begin)
79         if off < 0 || off >= torrentLength {
80                 panic("invalid request")
81         }
82         return
83 }
84
85 func validateInfo(info *metainfo.Info) error {
86         if len(info.Pieces)%20 != 0 {
87                 return errors.New("pieces has invalid length")
88         }
89         if info.PieceLength == 0 {
90                 if info.TotalLength() != 0 {
91                         return errors.New("zero piece length")
92                 }
93         } else {
94                 if int((info.TotalLength()+info.PieceLength-1)/info.PieceLength) != info.NumPieces() {
95                         return errors.New("piece count and file lengths are at odds")
96                 }
97         }
98         return nil
99 }
100
101 func chunkIndexSpec(index pp.Integer, pieceLength, chunkSize pp.Integer) chunkSpec {
102         ret := chunkSpec{pp.Integer(index) * chunkSize, chunkSize}
103         if ret.Begin+ret.Length > pieceLength {
104                 ret.Length = pieceLength - ret.Begin
105         }
106         return ret
107 }
108
109 func connLessTrusted(l, r *connection) bool {
110         return l.netGoodPiecesDirtied() < r.netGoodPiecesDirtied()
111 }
112
113 func connIsIpv6(nc interface {
114         LocalAddr() net.Addr
115 }) bool {
116         ra := nc.LocalAddr()
117         rip := missinggo.AddrIP(ra)
118         return rip.To4() == nil && rip.To16() != nil
119 }
120
121 func clamp(min, value, max int64) int64 {
122         if min > max {
123                 panic("harumph")
124         }
125         if value < min {
126                 value = min
127         }
128         if value > max {
129                 value = max
130         }
131         return value
132 }
133
134 func max(as ...int64) int64 {
135         ret := as[0]
136         for _, a := range as[1:] {
137                 if a > ret {
138                         ret = a
139                 }
140         }
141         return ret
142 }
143
144 func min(as ...int64) int64 {
145         ret := as[0]
146         for _, a := range as[1:] {
147                 if a < ret {
148                         ret = a
149                 }
150         }
151         return ret
152 }
153
154 var unlimited = rate.NewLimiter(rate.Inf, 0)
155
156 type (
157         pieceIndex = int
158         InfoHash   = metainfo.Hash
159 )