transmission 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +0 -0
- data/LICENSE +23 -0
- data/README +50 -0
- data/Rakefile +41 -0
- data/ext/bencode.c +335 -0
- data/ext/bencode.h +64 -0
- data/ext/choking.c +335 -0
- data/ext/choking.h +30 -0
- data/ext/clients.c +90 -0
- data/ext/clients.h +25 -0
- data/ext/completion.c +266 -0
- data/ext/completion.h +67 -0
- data/ext/extconf.rb +3 -0
- data/ext/fastresume.h +375 -0
- data/ext/fdlimit.c +297 -0
- data/ext/fdlimit.h +36 -0
- data/ext/inout.c +620 -0
- data/ext/inout.h +38 -0
- data/ext/internal.h +202 -0
- data/ext/metainfo.c +339 -0
- data/ext/metainfo.h +44 -0
- data/ext/net.c +405 -0
- data/ext/net.h +54 -0
- data/ext/peer.c +584 -0
- data/ext/peer.h +55 -0
- data/ext/peermessages.h +326 -0
- data/ext/peerparse.h +564 -0
- data/ext/peerutils.h +394 -0
- data/ext/platform.c +196 -0
- data/ext/platform.h +63 -0
- data/ext/r_transmission.c +1135 -0
- data/ext/ratecontrol.c +170 -0
- data/ext/ratecontrol.h +33 -0
- data/ext/sha1.c +235 -0
- data/ext/sha1.h +68 -0
- data/ext/tracker.c +767 -0
- data/ext/tracker.h +53 -0
- data/ext/transmission.c +776 -0
- data/ext/transmission.h +317 -0
- data/ext/utils.c +142 -0
- data/ext/utils.h +164 -0
- data/lib/transmission.rb +75 -0
- metadata +98 -0
data/ext/clients.h
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
/******************************************************************************
|
2
|
+
* $Id: clients.h 261 2006-05-29 21:27:31Z titer $
|
3
|
+
*
|
4
|
+
* Copyright (c) 2005 Transmission authors and contributors
|
5
|
+
*
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a
|
7
|
+
* copy of this software and associated documentation files (the "Software"),
|
8
|
+
* to deal in the Software without restriction, including without limitation
|
9
|
+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
10
|
+
* and/or sell copies of the Software, and to permit persons to whom the
|
11
|
+
* Software is furnished to do so, subject to the following conditions:
|
12
|
+
*
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
14
|
+
* all copies or substantial portions of the Software.
|
15
|
+
*
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
22
|
+
* DEALINGS IN THE SOFTWARE.
|
23
|
+
*****************************************************************************/
|
24
|
+
|
25
|
+
char * tr_clientForId( uint8_t * );
|
data/ext/completion.c
ADDED
@@ -0,0 +1,266 @@
|
|
1
|
+
/******************************************************************************
|
2
|
+
* $Id: completion.c 261 2006-05-29 21:27:31Z titer $
|
3
|
+
*
|
4
|
+
* Copyright (c) 2005 Transmission authors and contributors
|
5
|
+
*
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a
|
7
|
+
* copy of this software and associated documentation files (the "Software"),
|
8
|
+
* to deal in the Software without restriction, including without limitation
|
9
|
+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
10
|
+
* and/or sell copies of the Software, and to permit persons to whom the
|
11
|
+
* Software is furnished to do so, subject to the following conditions:
|
12
|
+
*
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
14
|
+
* all copies or substantial portions of the Software.
|
15
|
+
*
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
22
|
+
* DEALINGS IN THE SOFTWARE.
|
23
|
+
*****************************************************************************/
|
24
|
+
|
25
|
+
#include "transmission.h"
|
26
|
+
|
27
|
+
tr_completion_t * tr_cpInit( tr_torrent_t * tor )
|
28
|
+
{
|
29
|
+
tr_completion_t * cp;
|
30
|
+
|
31
|
+
cp = malloc( sizeof( tr_completion_t ) );
|
32
|
+
cp->tor = tor;
|
33
|
+
cp->blockBitfield = malloc( ( tor->blockCount + 7 ) / 8 );
|
34
|
+
cp->blockDownloaders = malloc( tor->blockCount );
|
35
|
+
cp->pieceBitfield = malloc( ( tor->info.pieceCount + 7 ) / 8 );
|
36
|
+
cp->missingBlocks = malloc( tor->info.pieceCount * sizeof( int ) );
|
37
|
+
|
38
|
+
tr_cpReset( cp );
|
39
|
+
|
40
|
+
return cp;
|
41
|
+
}
|
42
|
+
|
43
|
+
void tr_cpClose( tr_completion_t * cp )
|
44
|
+
{
|
45
|
+
free( cp->blockBitfield );
|
46
|
+
free( cp->blockDownloaders );
|
47
|
+
free( cp->pieceBitfield );
|
48
|
+
free( cp->missingBlocks );
|
49
|
+
free( cp );
|
50
|
+
}
|
51
|
+
|
52
|
+
void tr_cpReset( tr_completion_t * cp )
|
53
|
+
{
|
54
|
+
tr_torrent_t * tor = cp->tor;
|
55
|
+
int i;
|
56
|
+
|
57
|
+
cp->blockCount = 0;
|
58
|
+
memset( cp->blockBitfield, 0, ( tor->blockCount + 7 ) / 8 );
|
59
|
+
memset( cp->blockDownloaders, 0, tor->blockCount );
|
60
|
+
memset( cp->pieceBitfield, 0, ( tor->info.pieceCount + 7 ) / 8 );
|
61
|
+
for( i = 0; i < tor->info.pieceCount; i++ )
|
62
|
+
{
|
63
|
+
cp->missingBlocks[i] = tr_pieceCountBlocks( i );
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
float tr_cpCompletionAsFloat( tr_completion_t * cp )
|
68
|
+
{
|
69
|
+
return (float) cp->blockCount / (float) cp->tor->blockCount;
|
70
|
+
}
|
71
|
+
|
72
|
+
uint64_t tr_cpLeftBytes( tr_completion_t * cp )
|
73
|
+
{
|
74
|
+
tr_torrent_t * tor = cp->tor;
|
75
|
+
uint64_t left;
|
76
|
+
left = (uint64_t) ( cp->tor->blockCount - cp->blockCount ) *
|
77
|
+
(uint64_t) tor->blockSize;
|
78
|
+
if( !tr_bitfieldHas( cp->blockBitfield, cp->tor->blockCount - 1 ) &&
|
79
|
+
tor->info.totalSize % tor->blockSize )
|
80
|
+
{
|
81
|
+
left += tor->info.totalSize % tor->blockSize;
|
82
|
+
left -= tor->blockSize;
|
83
|
+
}
|
84
|
+
return left;
|
85
|
+
}
|
86
|
+
|
87
|
+
/* Pieces */
|
88
|
+
int tr_cpPieceIsComplete( tr_completion_t * cp, int piece )
|
89
|
+
{
|
90
|
+
return tr_bitfieldHas( cp->pieceBitfield, piece );
|
91
|
+
}
|
92
|
+
|
93
|
+
uint8_t * tr_cpPieceBitfield( tr_completion_t * cp )
|
94
|
+
{
|
95
|
+
return cp->pieceBitfield;
|
96
|
+
}
|
97
|
+
|
98
|
+
void tr_cpPieceAdd( tr_completion_t * cp, int piece )
|
99
|
+
{
|
100
|
+
tr_torrent_t * tor = cp->tor;
|
101
|
+
int startBlock, endBlock, i;
|
102
|
+
|
103
|
+
startBlock = tr_pieceStartBlock( piece );
|
104
|
+
endBlock = startBlock + tr_pieceCountBlocks( piece );
|
105
|
+
for( i = startBlock; i < endBlock; i++ )
|
106
|
+
{
|
107
|
+
tr_cpBlockAdd( cp, i );
|
108
|
+
}
|
109
|
+
|
110
|
+
tr_bitfieldAdd( cp->pieceBitfield, piece );
|
111
|
+
}
|
112
|
+
|
113
|
+
/* Blocks */
|
114
|
+
void tr_cpDownloaderAdd( tr_completion_t * cp, int block )
|
115
|
+
{
|
116
|
+
tr_torrent_t * tor = cp->tor;
|
117
|
+
if( !cp->blockDownloaders[block] && !tr_cpBlockIsComplete( cp, block ) )
|
118
|
+
{
|
119
|
+
cp->missingBlocks[tr_blockPiece(block)]--;
|
120
|
+
}
|
121
|
+
(cp->blockDownloaders[block])++;
|
122
|
+
}
|
123
|
+
|
124
|
+
void tr_cpDownloaderRem( tr_completion_t * cp, int block )
|
125
|
+
{
|
126
|
+
tr_torrent_t * tor = cp->tor;
|
127
|
+
(cp->blockDownloaders[block])--;
|
128
|
+
if( !cp->blockDownloaders[block] && !tr_cpBlockIsComplete( cp, block ) )
|
129
|
+
{
|
130
|
+
cp->missingBlocks[tr_blockPiece(block)]++;
|
131
|
+
}
|
132
|
+
}
|
133
|
+
|
134
|
+
int tr_cpBlockIsComplete( tr_completion_t * cp, int block )
|
135
|
+
{
|
136
|
+
return tr_bitfieldHas( cp->blockBitfield, block );
|
137
|
+
}
|
138
|
+
|
139
|
+
void tr_cpBlockAdd( tr_completion_t * cp, int block )
|
140
|
+
{
|
141
|
+
tr_torrent_t * tor = cp->tor;
|
142
|
+
if( !tr_cpBlockIsComplete( cp, block ) )
|
143
|
+
{
|
144
|
+
(cp->blockCount)++;
|
145
|
+
if( !cp->blockDownloaders[block] )
|
146
|
+
{
|
147
|
+
(cp->missingBlocks[tr_blockPiece(block)])--;
|
148
|
+
}
|
149
|
+
}
|
150
|
+
tr_bitfieldAdd( cp->blockBitfield, block );
|
151
|
+
}
|
152
|
+
|
153
|
+
void tr_cpBlockRem( tr_completion_t * cp, int block )
|
154
|
+
{
|
155
|
+
tr_torrent_t * tor = cp->tor;
|
156
|
+
if( tr_cpBlockIsComplete( cp, block ) )
|
157
|
+
{
|
158
|
+
(cp->blockCount)--;
|
159
|
+
if( !cp->blockDownloaders[block] )
|
160
|
+
{
|
161
|
+
(cp->missingBlocks[tr_blockPiece(block)])++;
|
162
|
+
}
|
163
|
+
}
|
164
|
+
tr_bitfieldRem( cp->blockBitfield, block );
|
165
|
+
}
|
166
|
+
|
167
|
+
uint8_t * tr_cpBlockBitfield( tr_completion_t * cp )
|
168
|
+
{
|
169
|
+
return cp->blockBitfield;
|
170
|
+
}
|
171
|
+
|
172
|
+
void tr_cpBlockBitfieldSet( tr_completion_t * cp, uint8_t * bitfield )
|
173
|
+
{
|
174
|
+
tr_torrent_t * tor = cp->tor;
|
175
|
+
int i, j;
|
176
|
+
int startBlock, endBlock;
|
177
|
+
int pieceComplete;
|
178
|
+
|
179
|
+
for( i = 0; i < cp->tor->info.pieceCount; i++ )
|
180
|
+
{
|
181
|
+
startBlock = tr_pieceStartBlock( i );
|
182
|
+
endBlock = startBlock + tr_pieceCountBlocks( i );
|
183
|
+
pieceComplete = 1;
|
184
|
+
|
185
|
+
for( j = startBlock; j < endBlock; j++ )
|
186
|
+
{
|
187
|
+
if( tr_bitfieldHas( bitfield, j ) )
|
188
|
+
{
|
189
|
+
tr_cpBlockAdd( cp, j );
|
190
|
+
}
|
191
|
+
else
|
192
|
+
{
|
193
|
+
pieceComplete = 0;
|
194
|
+
}
|
195
|
+
}
|
196
|
+
if( pieceComplete )
|
197
|
+
{
|
198
|
+
tr_cpPieceAdd( cp, i );
|
199
|
+
}
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
int tr_cpMissingBlockInPiece( tr_completion_t * cp, int piece )
|
204
|
+
{
|
205
|
+
tr_torrent_t * tor = cp->tor;
|
206
|
+
int start, count, end, i;
|
207
|
+
|
208
|
+
start = tr_pieceStartBlock( piece );
|
209
|
+
count = tr_pieceCountBlocks( piece );
|
210
|
+
end = start + count;
|
211
|
+
|
212
|
+
for( i = start; i < end; i++ )
|
213
|
+
{
|
214
|
+
if( tr_cpBlockIsComplete( cp, i ) || cp->blockDownloaders[i] )
|
215
|
+
{
|
216
|
+
continue;
|
217
|
+
}
|
218
|
+
return i;
|
219
|
+
}
|
220
|
+
|
221
|
+
return -1;
|
222
|
+
}
|
223
|
+
|
224
|
+
int tr_cpMostMissingBlockInPiece( tr_completion_t * cp, int piece,
|
225
|
+
int * downloaders )
|
226
|
+
{
|
227
|
+
tr_torrent_t * tor = cp->tor;
|
228
|
+
int start, count, end, i;
|
229
|
+
int * pool, poolSize, min, ret;
|
230
|
+
|
231
|
+
start = tr_pieceStartBlock( piece );
|
232
|
+
count = tr_pieceCountBlocks( piece );
|
233
|
+
end = start + count;
|
234
|
+
|
235
|
+
pool = malloc( count * sizeof( int ) );
|
236
|
+
poolSize = 0;
|
237
|
+
min = 255;
|
238
|
+
|
239
|
+
for( i = start; i < end; i++ )
|
240
|
+
{
|
241
|
+
if( tr_cpBlockIsComplete( cp, i ) || cp->blockDownloaders[i] > min )
|
242
|
+
{
|
243
|
+
continue;
|
244
|
+
}
|
245
|
+
if( cp->blockDownloaders[i] < min )
|
246
|
+
{
|
247
|
+
min = cp->blockDownloaders[i];
|
248
|
+
poolSize = 0;
|
249
|
+
}
|
250
|
+
if( cp->blockDownloaders[i] <= min )
|
251
|
+
{
|
252
|
+
pool[poolSize++] = i;
|
253
|
+
}
|
254
|
+
}
|
255
|
+
|
256
|
+
if( poolSize < 1 )
|
257
|
+
{
|
258
|
+
return -1;
|
259
|
+
}
|
260
|
+
|
261
|
+
ret = pool[0];
|
262
|
+
free( pool );
|
263
|
+
*downloaders = min;
|
264
|
+
return ret;
|
265
|
+
}
|
266
|
+
|
data/ext/completion.h
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
/******************************************************************************
|
2
|
+
* $Id: completion.h 261 2006-05-29 21:27:31Z titer $
|
3
|
+
*
|
4
|
+
* Copyright (c) 2005 Transmission authors and contributors
|
5
|
+
*
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a
|
7
|
+
* copy of this software and associated documentation files (the "Software"),
|
8
|
+
* to deal in the Software without restriction, including without limitation
|
9
|
+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
10
|
+
* and/or sell copies of the Software, and to permit persons to whom the
|
11
|
+
* Software is furnished to do so, subject to the following conditions:
|
12
|
+
*
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
14
|
+
* all copies or substantial portions of the Software.
|
15
|
+
*
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
22
|
+
* DEALINGS IN THE SOFTWARE.
|
23
|
+
*****************************************************************************/
|
24
|
+
|
25
|
+
struct tr_completion_s
|
26
|
+
{
|
27
|
+
tr_torrent_t * tor;
|
28
|
+
uint8_t * blockBitfield;
|
29
|
+
uint8_t * blockDownloaders;
|
30
|
+
int blockCount;
|
31
|
+
uint8_t * pieceBitfield;
|
32
|
+
int * missingBlocks;
|
33
|
+
};
|
34
|
+
|
35
|
+
tr_completion_t * tr_cpInit( tr_torrent_t * );
|
36
|
+
void tr_cpClose( tr_completion_t * );
|
37
|
+
void tr_cpReset( tr_completion_t * );
|
38
|
+
|
39
|
+
/* General */
|
40
|
+
float tr_cpCompletionAsFloat( tr_completion_t * );
|
41
|
+
static inline int tr_cpIsSeeding( tr_completion_t * cp )
|
42
|
+
{
|
43
|
+
return ( cp->blockCount == cp->tor->blockCount );
|
44
|
+
}
|
45
|
+
uint64_t tr_cpLeftBytes( tr_completion_t * );
|
46
|
+
|
47
|
+
/* Pieces */
|
48
|
+
int tr_cpPieceIsComplete( tr_completion_t *, int piece );
|
49
|
+
uint8_t * tr_cpPieceBitfield( tr_completion_t * );
|
50
|
+
void tr_cpPieceAdd( tr_completion_t *, int piece );
|
51
|
+
|
52
|
+
/* Blocks */
|
53
|
+
void tr_cpDownloaderAdd( tr_completion_t *, int block );
|
54
|
+
void tr_cpDownloaderRem( tr_completion_t *, int block );
|
55
|
+
int tr_cpBlockIsComplete( tr_completion_t *, int block );
|
56
|
+
void tr_cpBlockAdd( tr_completion_t *, int block );
|
57
|
+
void tr_cpBlockRem( tr_completion_t *, int block );
|
58
|
+
uint8_t * tr_cpBlockBitfield( tr_completion_t * );
|
59
|
+
void tr_cpBlockBitfieldSet( tr_completion_t *, uint8_t * );
|
60
|
+
/* Missing = we don't have it and we are not getting it from any peer yet */
|
61
|
+
static inline int tr_cpMissingBlocksForPiece( tr_completion_t * cp, int piece )
|
62
|
+
{
|
63
|
+
return cp->missingBlocks[piece];
|
64
|
+
}
|
65
|
+
int tr_cpMissingBlockInPiece( tr_completion_t *, int piece );
|
66
|
+
int tr_cpMostMissingBlockInPiece( tr_completion_t *, int piece,
|
67
|
+
int * downloaders );
|
data/ext/extconf.rb
ADDED
data/ext/fastresume.h
ADDED
@@ -0,0 +1,375 @@
|
|
1
|
+
/******************************************************************************
|
2
|
+
* $Id: fastresume.h 326 2006-06-11 04:32:41Z joshe $
|
3
|
+
*
|
4
|
+
* Copyright (c) 2005-2006 Transmission authors and contributors
|
5
|
+
*
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a
|
7
|
+
* copy of this software and associated documentation files (the "Software"),
|
8
|
+
* to deal in the Software without restriction, including without limitation
|
9
|
+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
10
|
+
* and/or sell copies of the Software, and to permit persons to whom the
|
11
|
+
* Software is furnished to do so, subject to the following conditions:
|
12
|
+
*
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
14
|
+
* all copies or substantial portions of the Software.
|
15
|
+
*
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
22
|
+
* DEALINGS IN THE SOFTWARE.
|
23
|
+
*****************************************************************************/
|
24
|
+
|
25
|
+
/***********************************************************************
|
26
|
+
* Fast resume
|
27
|
+
***********************************************************************
|
28
|
+
* The format of the resume file is a 4 byte format version (currently 1),
|
29
|
+
* followed by several variable-sized blocks of data. Each block is
|
30
|
+
* preceded by a 1 byte ID and a 4 byte length. The currently recognized
|
31
|
+
* IDs are defined below by the FR_ID_* macros. The length does not include
|
32
|
+
* the 5 bytes for the ID and length.
|
33
|
+
*
|
34
|
+
* The name of the resume file is "resume.<hash>".
|
35
|
+
*
|
36
|
+
* All values are stored in the native endianness. Moving a
|
37
|
+
* libtransmission resume file from an architecture to another will not
|
38
|
+
* work, although it will not hurt either (the version will be wrong,
|
39
|
+
* so the resume file will not be read).
|
40
|
+
**********************************************************************/
|
41
|
+
|
42
|
+
/* progress data:
|
43
|
+
* - 4 bytes * number of files: mtimes of files
|
44
|
+
* - 1 bit * number of blocks: whether we have the block or not
|
45
|
+
* - 4 bytes * number of pieces (byte aligned): the pieces that have
|
46
|
+
* been completed or started in each slot
|
47
|
+
*/
|
48
|
+
#define FR_ID_PROGRESS 0x01
|
49
|
+
/* number of bytes downloaded */
|
50
|
+
#define FR_ID_DOWNLOADED 0x02
|
51
|
+
/* number of bytes uploaded */
|
52
|
+
#define FR_ID_UPLOADED 0x03
|
53
|
+
|
54
|
+
/* macros for the length of various pieces of the progress data */
|
55
|
+
#define FR_MTIME_LEN( t ) \
|
56
|
+
( 4 * (t)->info.fileCount )
|
57
|
+
#define FR_BLOCK_BITFIELD_LEN( t ) \
|
58
|
+
( ( (t)->blockCount + 7 ) / 8 )
|
59
|
+
#define FR_SLOTPIECE_LEN( t ) \
|
60
|
+
( 4 * (t)->info.pieceCount )
|
61
|
+
#define FR_PROGRESS_LEN( t ) \
|
62
|
+
( FR_MTIME_LEN( t ) + FR_BLOCK_BITFIELD_LEN( t ) + FR_SLOTPIECE_LEN( t ) )
|
63
|
+
|
64
|
+
static char * fastResumeFileName( tr_io_t * io )
|
65
|
+
{
|
66
|
+
char * ret;
|
67
|
+
|
68
|
+
asprintf( &ret, "%s/resume.%s", tr_getCacheDirectory(),
|
69
|
+
io->tor->info.hashString );
|
70
|
+
|
71
|
+
return ret;
|
72
|
+
}
|
73
|
+
|
74
|
+
static int fastResumeMTimes( tr_io_t * io, int * tab )
|
75
|
+
{
|
76
|
+
tr_torrent_t * tor = io->tor;
|
77
|
+
tr_info_t * inf = &tor->info;
|
78
|
+
|
79
|
+
int i;
|
80
|
+
char * path;
|
81
|
+
struct stat sb;
|
82
|
+
|
83
|
+
for( i = 0; i < inf->fileCount; i++ )
|
84
|
+
{
|
85
|
+
asprintf( &path, "%s/%s", tor->destination, inf->files[i].name );
|
86
|
+
if( stat( path, &sb ) )
|
87
|
+
{
|
88
|
+
tr_err( "Could not stat '%s'", path );
|
89
|
+
free( path );
|
90
|
+
return 1;
|
91
|
+
}
|
92
|
+
if( ( sb.st_mode & S_IFMT ) != S_IFREG )
|
93
|
+
{
|
94
|
+
tr_err( "Wrong st_mode for '%s'", path );
|
95
|
+
free( path );
|
96
|
+
return 1;
|
97
|
+
}
|
98
|
+
free( path );
|
99
|
+
|
100
|
+
#ifdef SYS_DARWIN
|
101
|
+
tab[i] = ( sb.st_mtimespec.tv_sec & 0x7FFFFFFF );
|
102
|
+
#else
|
103
|
+
tab[i] = ( sb.st_mtime & 0x7FFFFFFF );
|
104
|
+
#endif
|
105
|
+
}
|
106
|
+
|
107
|
+
return 0;
|
108
|
+
}
|
109
|
+
|
110
|
+
static inline void fastResumeWriteData( uint8_t id, void * data, uint32_t size,
|
111
|
+
uint32_t count, FILE * file )
|
112
|
+
{
|
113
|
+
uint32_t datalen = size * count;
|
114
|
+
|
115
|
+
fwrite( &id, 1, 1, file );
|
116
|
+
fwrite( &datalen, 4, 1, file );
|
117
|
+
fwrite( data, size, count, file );
|
118
|
+
}
|
119
|
+
|
120
|
+
static void fastResumeSave( tr_io_t * io )
|
121
|
+
{
|
122
|
+
tr_torrent_t * tor = io->tor;
|
123
|
+
|
124
|
+
FILE * file;
|
125
|
+
int version = 1;
|
126
|
+
char * path;
|
127
|
+
uint8_t * buf;
|
128
|
+
|
129
|
+
buf = malloc( FR_PROGRESS_LEN( tor ) );
|
130
|
+
|
131
|
+
/* Get file sizes */
|
132
|
+
if( fastResumeMTimes( io, (int*)buf ) )
|
133
|
+
{
|
134
|
+
free( buf );
|
135
|
+
return;
|
136
|
+
}
|
137
|
+
|
138
|
+
/* Create/overwrite the resume file */
|
139
|
+
path = fastResumeFileName( io );
|
140
|
+
if( !( file = fopen( path, "w" ) ) )
|
141
|
+
{
|
142
|
+
tr_err( "Could not open '%s' for writing", path );
|
143
|
+
free( buf );
|
144
|
+
free( path );
|
145
|
+
return;
|
146
|
+
}
|
147
|
+
|
148
|
+
/* Write format version */
|
149
|
+
fwrite( &version, 4, 1, file );
|
150
|
+
|
151
|
+
/* Build and copy the bitfield for blocks */
|
152
|
+
memcpy(buf + FR_MTIME_LEN( tor ), tr_cpBlockBitfield( tor->completion ),
|
153
|
+
FR_BLOCK_BITFIELD_LEN( tor ) );
|
154
|
+
|
155
|
+
/* Copy the 'slotPiece' table */
|
156
|
+
memcpy(buf + FR_MTIME_LEN( tor ) + FR_BLOCK_BITFIELD_LEN( tor ),
|
157
|
+
io->slotPiece, FR_SLOTPIECE_LEN( tor ) );
|
158
|
+
|
159
|
+
/* Write progress data */
|
160
|
+
fastResumeWriteData( FR_ID_PROGRESS, buf, 1, FR_PROGRESS_LEN( tor ), file );
|
161
|
+
free( buf );
|
162
|
+
|
163
|
+
/* Write download and upload totals */
|
164
|
+
fastResumeWriteData( FR_ID_DOWNLOADED, &tor->downloaded, 8, 1, file );
|
165
|
+
fastResumeWriteData( FR_ID_UPLOADED, &tor->uploaded, 8, 1, file );
|
166
|
+
|
167
|
+
fclose( file );
|
168
|
+
|
169
|
+
tr_dbg( "Resume file '%s' written", path );
|
170
|
+
free( path );
|
171
|
+
}
|
172
|
+
|
173
|
+
static int fastResumeLoadProgress( tr_io_t * io, FILE * file )
|
174
|
+
{
|
175
|
+
tr_torrent_t * tor = io->tor;
|
176
|
+
tr_info_t * inf = &tor->info;
|
177
|
+
|
178
|
+
int * fileMTimes;
|
179
|
+
int i, j;
|
180
|
+
uint8_t * buf;
|
181
|
+
size_t len;
|
182
|
+
|
183
|
+
len = FR_PROGRESS_LEN( tor );
|
184
|
+
buf = calloc( len, 1 );
|
185
|
+
if( len != fread( buf, 1, len, file ) )
|
186
|
+
{
|
187
|
+
tr_inf( "Could not read from resume file" );
|
188
|
+
free( buf );
|
189
|
+
return 1;
|
190
|
+
}
|
191
|
+
|
192
|
+
/* Compare file mtimes */
|
193
|
+
fileMTimes = malloc( FR_MTIME_LEN( tor ) );
|
194
|
+
if( fastResumeMTimes( io, fileMTimes ) )
|
195
|
+
{
|
196
|
+
free( buf );
|
197
|
+
free( fileMTimes );
|
198
|
+
return 1;
|
199
|
+
}
|
200
|
+
if( memcmp( fileMTimes, buf, FR_MTIME_LEN( tor ) ) )
|
201
|
+
{
|
202
|
+
tr_inf( "File mtimes don't match" );
|
203
|
+
free( buf );
|
204
|
+
free( fileMTimes );
|
205
|
+
return 1;
|
206
|
+
}
|
207
|
+
free( fileMTimes );
|
208
|
+
|
209
|
+
/* Copy the bitfield for blocks and fill blockHave */
|
210
|
+
tr_cpBlockBitfieldSet( tor->completion, buf + FR_MTIME_LEN( tor ) );
|
211
|
+
|
212
|
+
/* Copy the 'slotPiece' table */
|
213
|
+
memcpy( io->slotPiece, buf + FR_MTIME_LEN( tor ) +
|
214
|
+
FR_BLOCK_BITFIELD_LEN( tor ), FR_SLOTPIECE_LEN( tor ) );
|
215
|
+
|
216
|
+
free( buf );
|
217
|
+
|
218
|
+
/* Update io->pieceSlot, io->slotsUsed, and tor->bitfield */
|
219
|
+
io->slotsUsed = 0;
|
220
|
+
for( i = 0; i < inf->pieceCount; i++ )
|
221
|
+
{
|
222
|
+
io->pieceSlot[i] = -1;
|
223
|
+
for( j = 0; j < inf->pieceCount; j++ )
|
224
|
+
{
|
225
|
+
if( io->slotPiece[j] == i )
|
226
|
+
{
|
227
|
+
// tr_dbg( "Has piece %d in slot %d", i, j );
|
228
|
+
io->pieceSlot[i] = j;
|
229
|
+
io->slotsUsed = MAX( io->slotsUsed, j + 1 );
|
230
|
+
break;
|
231
|
+
}
|
232
|
+
}
|
233
|
+
}
|
234
|
+
// tr_dbg( "Slot used: %d", io->slotsUsed );
|
235
|
+
|
236
|
+
return 0;
|
237
|
+
}
|
238
|
+
|
239
|
+
static int fastResumeLoadOld( tr_io_t * io, FILE * file )
|
240
|
+
{
|
241
|
+
tr_torrent_t * tor = io->tor;
|
242
|
+
|
243
|
+
int size;
|
244
|
+
|
245
|
+
/* Check the size */
|
246
|
+
size = 4 + FR_PROGRESS_LEN( tor );
|
247
|
+
fseek( file, 0, SEEK_END );
|
248
|
+
if( ftell( file ) != size )
|
249
|
+
{
|
250
|
+
tr_inf( "Wrong size for resume file (%d bytes, %d expected)",
|
251
|
+
ftell( file ), size );
|
252
|
+
fclose( file );
|
253
|
+
return 1;
|
254
|
+
}
|
255
|
+
|
256
|
+
/* load progress information */
|
257
|
+
fseek( file, 4, SEEK_SET );
|
258
|
+
if( fastResumeLoadProgress( io, file ) )
|
259
|
+
{
|
260
|
+
fclose( file );
|
261
|
+
return 1;
|
262
|
+
}
|
263
|
+
|
264
|
+
fclose( file );
|
265
|
+
|
266
|
+
tr_inf( "Fast resuming successful (version 0)" );
|
267
|
+
|
268
|
+
return 0;
|
269
|
+
}
|
270
|
+
|
271
|
+
static int fastResumeLoad( tr_io_t * io )
|
272
|
+
{
|
273
|
+
tr_torrent_t * tor = io->tor;
|
274
|
+
|
275
|
+
FILE * file;
|
276
|
+
int version = 0;
|
277
|
+
char * path;
|
278
|
+
uint8_t id;
|
279
|
+
uint32_t len;
|
280
|
+
int ret;
|
281
|
+
|
282
|
+
/* Open resume file */
|
283
|
+
path = fastResumeFileName( io );
|
284
|
+
if( !( file = fopen( path, "r" ) ) )
|
285
|
+
{
|
286
|
+
tr_inf( "Could not open '%s' for reading", path );
|
287
|
+
free( path );
|
288
|
+
return 1;
|
289
|
+
}
|
290
|
+
tr_dbg( "Resume file '%s' loaded", path );
|
291
|
+
free( path );
|
292
|
+
|
293
|
+
/* Check format version */
|
294
|
+
fread( &version, 4, 1, file );
|
295
|
+
if( 0 == version )
|
296
|
+
{
|
297
|
+
return fastResumeLoadOld( io, file );
|
298
|
+
}
|
299
|
+
if( 1 != version )
|
300
|
+
{
|
301
|
+
tr_inf( "Resume file has version %d, not supported", version );
|
302
|
+
fclose( file );
|
303
|
+
return 1;
|
304
|
+
}
|
305
|
+
|
306
|
+
ret = 1;
|
307
|
+
/* read each block of data */
|
308
|
+
while( 1 == fread( &id, 1, 1, file ) && 1 == fread( &len, 4, 1, file ) )
|
309
|
+
{
|
310
|
+
switch( id )
|
311
|
+
{
|
312
|
+
case FR_ID_PROGRESS:
|
313
|
+
/* read progress data */
|
314
|
+
if( (uint32_t)FR_PROGRESS_LEN( tor ) == len )
|
315
|
+
{
|
316
|
+
if( fastResumeLoadProgress( io, file ) )
|
317
|
+
{
|
318
|
+
if( feof( file ) || ferror( file ) )
|
319
|
+
{
|
320
|
+
fclose( file );
|
321
|
+
return 1;
|
322
|
+
}
|
323
|
+
}
|
324
|
+
else
|
325
|
+
{
|
326
|
+
ret = 0;
|
327
|
+
}
|
328
|
+
continue;
|
329
|
+
}
|
330
|
+
break;
|
331
|
+
|
332
|
+
case FR_ID_DOWNLOADED:
|
333
|
+
/* read download total */
|
334
|
+
if( 8 == len)
|
335
|
+
{
|
336
|
+
if( 1 != fread( &tor->downloaded, 8, 1, file ) )
|
337
|
+
{
|
338
|
+
fclose( file );
|
339
|
+
return 1;
|
340
|
+
}
|
341
|
+
continue;
|
342
|
+
}
|
343
|
+
break;
|
344
|
+
|
345
|
+
case FR_ID_UPLOADED:
|
346
|
+
/* read upload total */
|
347
|
+
if( 8 == len)
|
348
|
+
{
|
349
|
+
if( 1 != fread( &tor->uploaded, 8, 1, file ) )
|
350
|
+
{
|
351
|
+
fclose( file );
|
352
|
+
return 1;
|
353
|
+
}
|
354
|
+
continue;
|
355
|
+
}
|
356
|
+
break;
|
357
|
+
|
358
|
+
default:
|
359
|
+
break;
|
360
|
+
}
|
361
|
+
|
362
|
+
/* if we didn't read the data, seek past it */
|
363
|
+
tr_inf( "Skipping resume data type %02x, %u bytes", id, len );
|
364
|
+
fseek( file, len, SEEK_CUR );
|
365
|
+
}
|
366
|
+
|
367
|
+
fclose( file );
|
368
|
+
|
369
|
+
if( !ret )
|
370
|
+
{
|
371
|
+
tr_inf( "Fast resuming successful" );
|
372
|
+
}
|
373
|
+
|
374
|
+
return ret;
|
375
|
+
}
|