]> Sergey Matveev's repositories - btrtrc.git/blob - misc.go
Encapsulate torrent data, and provide os.File and mmap-based implementations
[btrtrc.git] / misc.go
1 package torrent
2
3 import (
4         "crypto"
5         "errors"
6         "fmt"
7         "math/rand"
8         "sync"
9         "time"
10
11         "bitbucket.org/anacrolix/go.torrent/peer_protocol"
12 )
13
14 const (
15         pieceHash          = crypto.SHA1
16         maxRequests        = 250        // Maximum pending requests we allow peers to send us.
17         chunkSize          = 0x4000     // 16KiB
18         BEP20              = "-GT0000-" // Peer ID client identifier prefix
19         nominalDialTimeout = time.Second * 30
20         minDialTimeout     = 5 * time.Second
21 )
22
23 type (
24         InfoHash [20]byte
25         pieceSum [20]byte
26 )
27
28 func (ih *InfoHash) AsString() string {
29         return string(ih[:])
30 }
31
32 func (ih *InfoHash) HexString() string {
33         return fmt.Sprintf("%x", ih[:])
34 }
35
36 type piecePriority byte
37
38 const (
39         piecePriorityNone piecePriority = iota
40         piecePriorityNormal
41         piecePriorityReadahead
42         piecePriorityNext
43         piecePriorityNow
44 )
45
46 type piece struct {
47         Hash              pieceSum
48         PendingChunkSpecs map[chunkSpec]struct{}
49         Hashing           bool
50         QueuedForHash     bool
51         EverHashed        bool
52         Event             sync.Cond
53         Priority          piecePriority
54 }
55
56 func (p *piece) shuffledPendingChunkSpecs() (css []chunkSpec) {
57         if len(p.PendingChunkSpecs) == 0 {
58                 return
59         }
60         css = make([]chunkSpec, 0, len(p.PendingChunkSpecs))
61         for cs := range p.PendingChunkSpecs {
62                 css = append(css, cs)
63         }
64         if len(css) <= 1 {
65                 return
66         }
67         for i := range css {
68                 j := rand.Intn(i + 1)
69                 css[i], css[j] = css[j], css[i]
70         }
71         return
72 }
73
74 func (p *piece) Complete() bool {
75         return len(p.PendingChunkSpecs) == 0 && p.EverHashed
76 }
77
78 func lastChunkSpec(pieceLength peer_protocol.Integer) (cs chunkSpec) {
79         cs.Begin = (pieceLength - 1) / chunkSize * chunkSize
80         cs.Length = pieceLength - cs.Begin
81         return
82 }
83
84 type chunkSpec struct {
85         Begin, Length peer_protocol.Integer
86 }
87
88 type request struct {
89         Index peer_protocol.Integer
90         chunkSpec
91 }
92
93 func newRequest(index, begin, length peer_protocol.Integer) request {
94         return request{index, chunkSpec{begin, length}}
95 }
96
97 var (
98         // Requested data not yet available.
99         ErrDataNotReady = errors.New("data not ready")
100 )
101
102 // The size in bytes of a metadata extension piece.
103 func metadataPieceSize(totalSize int, piece int) int {
104         ret := totalSize - piece*(1<<14)
105         if ret > 1<<14 {
106                 ret = 1 << 14
107         }
108         return ret
109 }