]> Sergey Matveev's repositories - btrtrc.git/blob - misc.go
sortimports
[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 int, 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 // Convert a net.Addr to its compact IP representation. Either 4 or 16 bytes
114 // per "yourip" field of http://www.bittorrent.org/beps/bep_0010.html.
115 func addrCompactIP(addr net.Addr) (string, error) {
116         host, _, err := net.SplitHostPort(addr.String())
117         if err != nil {
118                 return "", err
119         }
120         ip := net.ParseIP(host)
121         if v4 := ip.To4(); v4 != nil {
122                 if len(v4) != 4 {
123                         panic(v4)
124                 }
125                 return string(v4), nil
126         }
127         return string(ip.To16()), nil
128 }
129
130 func connIsIpv6(nc interface {
131         LocalAddr() net.Addr
132 }) bool {
133         ra := nc.LocalAddr()
134         rip := missinggo.AddrIP(ra)
135         return rip.To4() == nil && rip.To16() != nil
136 }
137
138 func clamp(min, value, max int64) int64 {
139         if min > max {
140                 panic("harumph")
141         }
142         if value < min {
143                 value = min
144         }
145         if value > max {
146                 value = max
147         }
148         return value
149 }
150
151 func max(as ...int64) int64 {
152         ret := as[0]
153         for _, a := range as[1:] {
154                 if a > ret {
155                         ret = a
156                 }
157         }
158         return ret
159 }
160
161 func min(as ...int64) int64 {
162         ret := as[0]
163         for _, a := range as[1:] {
164                 if a < ret {
165                         ret = a
166                 }
167         }
168         return ret
169 }
170
171 var unlimited = rate.NewLimiter(rate.Inf, 0)
172
173 type (
174         pieceIndex = int
175         InfoHash   = metainfo.Hash
176 )