]> Sergey Matveev's repositories - btrtrc.git/blob - misc.go
Break up client.go into several files and a few fixes
[btrtrc.git] / misc.go
1 package torrent
2
3 import (
4         "crypto"
5         "errors"
6         "os"
7         "path/filepath"
8         "time"
9
10         "bitbucket.org/anacrolix/go.torrent/peer_protocol"
11         metainfo "github.com/nsf/libtorgo/torrent"
12         "launchpad.net/gommap"
13 )
14
15 const (
16         PieceHash   = crypto.SHA1
17         maxRequests = 250
18         chunkSize   = 0x4000 // 16KiB
19         BEP20       = "-GT0000-"
20         dialTimeout = time.Second * 15
21 )
22
23 type InfoHash [20]byte
24
25 type pieceSum [20]byte
26
27 func copyHashSum(dst, src []byte) {
28         if len(dst) != len(src) || copy(dst, src) != len(dst) {
29                 panic("hash sum sizes differ")
30         }
31 }
32
33 func BytesInfoHash(b []byte) (ih InfoHash) {
34         if len(b) != len(ih) || copy(ih[:], b) != len(ih) {
35                 panic("bad infohash bytes")
36         }
37         return
38 }
39
40 type piece struct {
41         Hash              pieceSum
42         PendingChunkSpecs map[ChunkSpec]struct{}
43         Hashing           bool
44         QueuedForHash     bool
45         EverHashed        bool
46 }
47
48 func (p *piece) Complete() bool {
49         return len(p.PendingChunkSpecs) == 0 && p.EverHashed
50 }
51
52 func lastChunkSpec(pieceLength peer_protocol.Integer) (cs ChunkSpec) {
53         cs.Begin = (pieceLength - 1) / chunkSize * chunkSize
54         cs.Length = pieceLength - cs.Begin
55         return
56 }
57
58 type ChunkSpec struct {
59         Begin, Length peer_protocol.Integer
60 }
61
62 type Request struct {
63         Index peer_protocol.Integer
64         ChunkSpec
65 }
66
67 type pieceByBytesPendingSlice struct {
68         Pending, Indices []peer_protocol.Integer
69 }
70
71 func (pcs pieceByBytesPendingSlice) Len() int {
72         return len(pcs.Indices)
73 }
74
75 func (me pieceByBytesPendingSlice) Less(i, j int) bool {
76         return me.Pending[me.Indices[i]] < me.Pending[me.Indices[j]]
77 }
78
79 func (me pieceByBytesPendingSlice) Swap(i, j int) {
80         me.Indices[i], me.Indices[j] = me.Indices[j], me.Indices[i]
81 }
82
83 var (
84         ErrDataNotReady = errors.New("data not ready")
85 )
86
87 func mmapTorrentData(metaInfo *metainfo.MetaInfo, location string) (mms MMapSpan, err error) {
88         defer func() {
89                 if err != nil {
90                         mms.Close()
91                         mms = nil
92                 }
93         }()
94         for _, miFile := range metaInfo.Files {
95                 fileName := filepath.Join(append([]string{location, metaInfo.Name}, miFile.Path...)...)
96                 err = os.MkdirAll(filepath.Dir(fileName), 0777)
97                 if err != nil {
98                         return
99                 }
100                 var file *os.File
101                 file, err = os.OpenFile(fileName, os.O_CREATE|os.O_RDWR, 0666)
102                 if err != nil {
103                         return
104                 }
105                 func() {
106                         defer file.Close()
107                         var fi os.FileInfo
108                         fi, err = file.Stat()
109                         if err != nil {
110                                 return
111                         }
112                         if fi.Size() < miFile.Length {
113                                 err = file.Truncate(miFile.Length)
114                                 if err != nil {
115                                         return
116                                 }
117                         }
118                         var mMap gommap.MMap
119                         mMap, err = gommap.MapRegion(file.Fd(), 0, miFile.Length, gommap.PROT_READ|gommap.PROT_WRITE, gommap.MAP_SHARED)
120                         if err != nil {
121                                 return
122                         }
123                         if int64(len(mMap)) != miFile.Length {
124                                 panic("mmap has wrong length")
125                         }
126                         mms = append(mms, MMap{mMap})
127                 }()
128                 if err != nil {
129                         return
130                 }
131         }
132         return
133 }