transmission 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/peer.c
ADDED
@@ -0,0 +1,584 @@
|
|
1
|
+
/******************************************************************************
|
2
|
+
* $Id: peer.c 261 2006-05-29 21:27:31Z titer $
|
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
|
+
#include "transmission.h"
|
26
|
+
|
27
|
+
#define MAX_REQUEST_COUNT 32
|
28
|
+
#define OUR_REQUEST_COUNT 8 /* TODO: we should detect if we are on a
|
29
|
+
high-speed network and adapt */
|
30
|
+
|
31
|
+
typedef struct tr_request_s
|
32
|
+
{
|
33
|
+
int index;
|
34
|
+
int begin;
|
35
|
+
int length;
|
36
|
+
|
37
|
+
} tr_request_t;
|
38
|
+
|
39
|
+
struct tr_peer_s
|
40
|
+
{
|
41
|
+
struct in_addr addr;
|
42
|
+
in_port_t port;
|
43
|
+
|
44
|
+
#define PEER_STATUS_IDLE 1 /* Need to connect */
|
45
|
+
#define PEER_STATUS_CONNECTING 2 /* Trying to send handshake */
|
46
|
+
#define PEER_STATUS_HANDSHAKE 4 /* Waiting for peer's handshake */
|
47
|
+
#define PEER_STATUS_CONNECTED 8 /* Got peer's handshake */
|
48
|
+
int status;
|
49
|
+
int socket;
|
50
|
+
uint64_t date;
|
51
|
+
uint64_t keepAlive;
|
52
|
+
|
53
|
+
char amChoking;
|
54
|
+
char amInterested;
|
55
|
+
char peerChoking;
|
56
|
+
char peerInterested;
|
57
|
+
|
58
|
+
int optimistic;
|
59
|
+
uint64_t lastChoke;
|
60
|
+
|
61
|
+
uint8_t id[20];
|
62
|
+
|
63
|
+
/* The pieces that the peer has */
|
64
|
+
uint8_t * bitfield;
|
65
|
+
|
66
|
+
int goodPcs;
|
67
|
+
int badPcs;
|
68
|
+
int banned;
|
69
|
+
/* The pieces that the peer is contributing to */
|
70
|
+
uint8_t * blamefield;
|
71
|
+
/* The bad pieces that the peer has contributed to */
|
72
|
+
uint8_t * banfield;
|
73
|
+
|
74
|
+
uint8_t * buf;
|
75
|
+
int size;
|
76
|
+
int pos;
|
77
|
+
|
78
|
+
uint8_t * outMessages;
|
79
|
+
int outMessagesSize;
|
80
|
+
int outMessagesPos;
|
81
|
+
uint8_t outBlock[13+16384];
|
82
|
+
int outBlockSize;
|
83
|
+
int outBlockLoaded;
|
84
|
+
int outBlockSending;
|
85
|
+
|
86
|
+
int inRequestCount;
|
87
|
+
tr_request_t inRequests[OUR_REQUEST_COUNT];
|
88
|
+
int inIndex;
|
89
|
+
int inBegin;
|
90
|
+
int inLength;
|
91
|
+
uint64_t inTotal;
|
92
|
+
|
93
|
+
int outRequestCount;
|
94
|
+
tr_request_t outRequests[MAX_REQUEST_COUNT];
|
95
|
+
uint64_t outTotal;
|
96
|
+
uint64_t outDate;
|
97
|
+
int outSlow;
|
98
|
+
|
99
|
+
tr_ratecontrol_t * download;
|
100
|
+
};
|
101
|
+
|
102
|
+
#define peer_dbg( a... ) __peer_dbg( peer, ## a )
|
103
|
+
static void __peer_dbg( tr_peer_t * peer, char * msg, ... )
|
104
|
+
{
|
105
|
+
char string[256];
|
106
|
+
va_list args;
|
107
|
+
|
108
|
+
va_start( args, msg );
|
109
|
+
sprintf( string, "%08x:%04x ",
|
110
|
+
(uint32_t) peer->addr.s_addr, peer->port );
|
111
|
+
vsnprintf( &string[14], sizeof( string ) - 14, msg, args );
|
112
|
+
va_end( args );
|
113
|
+
|
114
|
+
tr_dbg( "%s", string );
|
115
|
+
}
|
116
|
+
|
117
|
+
#include "peermessages.h"
|
118
|
+
#include "peerutils.h"
|
119
|
+
#include "peerparse.h"
|
120
|
+
|
121
|
+
/***********************************************************************
|
122
|
+
* tr_peerAddOld
|
123
|
+
***********************************************************************
|
124
|
+
* Tries to add a peer given its IP and port (received from a tracker
|
125
|
+
* which doesn't support the "compact" extension).
|
126
|
+
**********************************************************************/
|
127
|
+
void tr_peerAddOld( tr_torrent_t * tor, char * ip, int port )
|
128
|
+
{
|
129
|
+
struct in_addr addr;
|
130
|
+
|
131
|
+
if( tr_netResolve( ip, &addr ) )
|
132
|
+
{
|
133
|
+
return;
|
134
|
+
}
|
135
|
+
|
136
|
+
addWithAddr( tor, addr, htons( port ) );
|
137
|
+
}
|
138
|
+
|
139
|
+
/***********************************************************************
|
140
|
+
* tr_peerAddCompact
|
141
|
+
***********************************************************************
|
142
|
+
* Tries to add a peer, using 'addr' and 'port' to connect to the peer.
|
143
|
+
**********************************************************************/
|
144
|
+
void tr_peerAddCompact( tr_torrent_t * tor, struct in_addr addr,
|
145
|
+
in_port_t port )
|
146
|
+
{
|
147
|
+
addWithAddr( tor, addr, port );
|
148
|
+
}
|
149
|
+
|
150
|
+
/***********************************************************************
|
151
|
+
* tr_peerInit
|
152
|
+
***********************************************************************
|
153
|
+
* Initializes a new peer.
|
154
|
+
**********************************************************************/
|
155
|
+
tr_peer_t * tr_peerInit( struct in_addr addr, in_port_t port, int s )
|
156
|
+
{
|
157
|
+
tr_peer_t * peer = peerInit();
|
158
|
+
|
159
|
+
peer->socket = s;
|
160
|
+
peer->addr = addr;
|
161
|
+
peer->port = port;
|
162
|
+
peer->status = PEER_STATUS_CONNECTING;
|
163
|
+
|
164
|
+
return peer;
|
165
|
+
}
|
166
|
+
|
167
|
+
void tr_peerAttach( tr_torrent_t * tor, tr_peer_t * peer )
|
168
|
+
{
|
169
|
+
peerAttach( tor, peer );
|
170
|
+
}
|
171
|
+
|
172
|
+
void tr_peerDestroy( tr_fd_t * fdlimit, tr_peer_t * peer )
|
173
|
+
{
|
174
|
+
if( peer->bitfield )
|
175
|
+
{
|
176
|
+
free( peer->bitfield );
|
177
|
+
}
|
178
|
+
if( peer->blamefield )
|
179
|
+
{
|
180
|
+
free( peer->blamefield );
|
181
|
+
}
|
182
|
+
if( peer->banfield )
|
183
|
+
{
|
184
|
+
free( peer->banfield );
|
185
|
+
}
|
186
|
+
if( peer->buf )
|
187
|
+
{
|
188
|
+
free( peer->buf );
|
189
|
+
}
|
190
|
+
if( peer->outMessages )
|
191
|
+
{
|
192
|
+
free( peer->outMessages );
|
193
|
+
}
|
194
|
+
if( peer->status > PEER_STATUS_IDLE )
|
195
|
+
{
|
196
|
+
tr_netClose( peer->socket );
|
197
|
+
tr_fdSocketClosed( fdlimit, 0 );
|
198
|
+
}
|
199
|
+
tr_rcClose( peer->download );
|
200
|
+
free( peer );
|
201
|
+
}
|
202
|
+
|
203
|
+
/***********************************************************************
|
204
|
+
* tr_peerRem
|
205
|
+
***********************************************************************
|
206
|
+
* Frees and closes everything related to the peer at index 'i', and
|
207
|
+
* removes it from the peers list.
|
208
|
+
**********************************************************************/
|
209
|
+
void tr_peerRem( tr_torrent_t * tor, int i )
|
210
|
+
{
|
211
|
+
tr_peer_t * peer = tor->peers[i];
|
212
|
+
int j;
|
213
|
+
|
214
|
+
for( j = 0; j < peer->inRequestCount; j++ )
|
215
|
+
{
|
216
|
+
tr_request_t * r;
|
217
|
+
int block;
|
218
|
+
|
219
|
+
r = &peer->inRequests[j];
|
220
|
+
block = tr_block( r->index,r->begin );
|
221
|
+
tr_cpDownloaderRem( tor->completion, block );
|
222
|
+
}
|
223
|
+
tr_peerDestroy( tor->fdlimit, peer );
|
224
|
+
tor->peerCount--;
|
225
|
+
memmove( &tor->peers[i], &tor->peers[i+1],
|
226
|
+
( tor->peerCount - i ) * sizeof( tr_peer_t * ) );
|
227
|
+
}
|
228
|
+
|
229
|
+
/***********************************************************************
|
230
|
+
* tr_peerRead
|
231
|
+
***********************************************************************
|
232
|
+
*
|
233
|
+
**********************************************************************/
|
234
|
+
int tr_peerRead( tr_torrent_t * tor, tr_peer_t * peer )
|
235
|
+
{
|
236
|
+
int ret;
|
237
|
+
|
238
|
+
/* Try to read */
|
239
|
+
for( ;; )
|
240
|
+
{
|
241
|
+
if( tor && !tr_rcCanTransfer( tor->globalDownload ) )
|
242
|
+
{
|
243
|
+
break;
|
244
|
+
}
|
245
|
+
|
246
|
+
if( peer->size < 1 )
|
247
|
+
{
|
248
|
+
peer->size = 1024;
|
249
|
+
peer->buf = malloc( peer->size );
|
250
|
+
}
|
251
|
+
else if( peer->pos >= peer->size )
|
252
|
+
{
|
253
|
+
peer->size *= 2;
|
254
|
+
peer->buf = realloc( peer->buf, peer->size );
|
255
|
+
}
|
256
|
+
/* Never read more than 1K each time, otherwise the rate
|
257
|
+
control is no use */
|
258
|
+
ret = tr_netRecv( peer->socket, &peer->buf[peer->pos],
|
259
|
+
MIN( 1024, peer->size - peer->pos ) );
|
260
|
+
if( ret & TR_NET_CLOSE )
|
261
|
+
{
|
262
|
+
peer_dbg( "connection closed" );
|
263
|
+
return 1;
|
264
|
+
}
|
265
|
+
else if( ret & TR_NET_BLOCK )
|
266
|
+
{
|
267
|
+
break;
|
268
|
+
}
|
269
|
+
peer->date = tr_date();
|
270
|
+
peer->pos += ret;
|
271
|
+
if( NULL != tor )
|
272
|
+
{
|
273
|
+
tr_rcTransferred( peer->download, ret );
|
274
|
+
tr_rcTransferred( tor->download, ret );
|
275
|
+
tr_rcTransferred( tor->globalDownload, ret );
|
276
|
+
if( parseBuf( tor, peer ) )
|
277
|
+
{
|
278
|
+
return 1;
|
279
|
+
}
|
280
|
+
}
|
281
|
+
else
|
282
|
+
{
|
283
|
+
if( parseBufHeader( peer ) )
|
284
|
+
{
|
285
|
+
return 1;
|
286
|
+
}
|
287
|
+
}
|
288
|
+
}
|
289
|
+
|
290
|
+
return 0;
|
291
|
+
}
|
292
|
+
|
293
|
+
uint64_t tr_peerDate( tr_peer_t * peer )
|
294
|
+
{
|
295
|
+
return peer->date;
|
296
|
+
}
|
297
|
+
|
298
|
+
/***********************************************************************
|
299
|
+
* tr_peerHash
|
300
|
+
***********************************************************************
|
301
|
+
*
|
302
|
+
**********************************************************************/
|
303
|
+
uint8_t * tr_peerHash( tr_peer_t * peer )
|
304
|
+
{
|
305
|
+
return parseBufHash( peer );
|
306
|
+
}
|
307
|
+
|
308
|
+
/***********************************************************************
|
309
|
+
* tr_peerPulse
|
310
|
+
***********************************************************************
|
311
|
+
*
|
312
|
+
**********************************************************************/
|
313
|
+
void tr_peerPulse( tr_torrent_t * tor )
|
314
|
+
{
|
315
|
+
int i, ret, size;
|
316
|
+
uint8_t * p;
|
317
|
+
tr_peer_t * peer;
|
318
|
+
|
319
|
+
if( tr_date() > tor->date + 1000 )
|
320
|
+
{
|
321
|
+
tor->date = tr_date();
|
322
|
+
|
323
|
+
for( i = 0; i < tor->peerCount; )
|
324
|
+
{
|
325
|
+
if( checkPeer( tor, i ) )
|
326
|
+
{
|
327
|
+
tr_peerRem( tor, i );
|
328
|
+
continue;
|
329
|
+
}
|
330
|
+
i++;
|
331
|
+
}
|
332
|
+
}
|
333
|
+
|
334
|
+
if( tor->status & TR_STATUS_STOPPING )
|
335
|
+
{
|
336
|
+
return;
|
337
|
+
}
|
338
|
+
|
339
|
+
/* Shuffle peers */
|
340
|
+
if( tor->peerCount > 1 )
|
341
|
+
{
|
342
|
+
peer = tor->peers[0];
|
343
|
+
memmove( &tor->peers[0], &tor->peers[1],
|
344
|
+
( tor->peerCount - 1 ) * sizeof( void * ) );
|
345
|
+
tor->peers[tor->peerCount - 1] = peer;
|
346
|
+
}
|
347
|
+
|
348
|
+
/* Handle peers */
|
349
|
+
for( i = 0; i < tor->peerCount; )
|
350
|
+
{
|
351
|
+
peer = tor->peers[i];
|
352
|
+
|
353
|
+
if( peer->status < PEER_STATUS_HANDSHAKE )
|
354
|
+
{
|
355
|
+
i++;
|
356
|
+
continue;
|
357
|
+
}
|
358
|
+
|
359
|
+
if( tr_peerRead( tor, tor->peers[i] ) )
|
360
|
+
{
|
361
|
+
goto dropPeer;
|
362
|
+
}
|
363
|
+
|
364
|
+
if( peer->status < PEER_STATUS_CONNECTED )
|
365
|
+
{
|
366
|
+
i++;
|
367
|
+
continue;
|
368
|
+
}
|
369
|
+
|
370
|
+
/* Try to write */
|
371
|
+
writeBegin:
|
372
|
+
|
373
|
+
/* Send all smaller messages regardless of the upload cap */
|
374
|
+
while( ( p = messagesPending( peer, &size ) ) )
|
375
|
+
{
|
376
|
+
ret = tr_netSend( peer->socket, p, size );
|
377
|
+
if( ret & TR_NET_CLOSE )
|
378
|
+
{
|
379
|
+
goto dropPeer;
|
380
|
+
}
|
381
|
+
else if( ret & TR_NET_BLOCK )
|
382
|
+
{
|
383
|
+
goto writeEnd;
|
384
|
+
}
|
385
|
+
messagesSent( peer, ret );
|
386
|
+
}
|
387
|
+
|
388
|
+
/* Send pieces if we can */
|
389
|
+
while( ( p = blockPending( tor, peer, &size ) ) )
|
390
|
+
{
|
391
|
+
if( !tr_rcCanTransfer( tor->globalUpload ) )
|
392
|
+
{
|
393
|
+
break;
|
394
|
+
}
|
395
|
+
|
396
|
+
ret = tr_netSend( peer->socket, p, size );
|
397
|
+
if( ret & TR_NET_CLOSE )
|
398
|
+
{
|
399
|
+
goto dropPeer;
|
400
|
+
}
|
401
|
+
else if( ret & TR_NET_BLOCK )
|
402
|
+
{
|
403
|
+
break;
|
404
|
+
}
|
405
|
+
|
406
|
+
blockSent( peer, ret );
|
407
|
+
tr_rcTransferred( tor->upload, ret );
|
408
|
+
tr_rcTransferred( tor->globalUpload, ret );
|
409
|
+
|
410
|
+
tor->uploaded += ret;
|
411
|
+
peer->outTotal += ret;
|
412
|
+
peer->outDate = tr_date();
|
413
|
+
|
414
|
+
/* In case this block is done, you may have messages
|
415
|
+
pending. Send them before we start the next block */
|
416
|
+
goto writeBegin;
|
417
|
+
}
|
418
|
+
writeEnd:
|
419
|
+
|
420
|
+
/* Ask for a block whenever possible */
|
421
|
+
if( !tr_cpIsSeeding( tor->completion ) &&
|
422
|
+
!peer->amInterested && tor->peerCount > TR_MAX_PEER_COUNT - 2 )
|
423
|
+
{
|
424
|
+
/* This peer is no use to us, and it seems there are
|
425
|
+
more */
|
426
|
+
peer_dbg( "not interesting" );
|
427
|
+
tr_peerRem( tor, i );
|
428
|
+
continue;
|
429
|
+
}
|
430
|
+
|
431
|
+
if( peer->amInterested && !peer->peerChoking && !peer->banned )
|
432
|
+
{
|
433
|
+
int block;
|
434
|
+
while( peer->inRequestCount < OUR_REQUEST_COUNT )
|
435
|
+
{
|
436
|
+
block = chooseBlock( tor, peer );
|
437
|
+
if( block < 0 )
|
438
|
+
{
|
439
|
+
break;
|
440
|
+
}
|
441
|
+
sendRequest( tor, peer, block );
|
442
|
+
}
|
443
|
+
}
|
444
|
+
|
445
|
+
i++;
|
446
|
+
continue;
|
447
|
+
|
448
|
+
dropPeer:
|
449
|
+
tr_peerRem( tor, i );
|
450
|
+
}
|
451
|
+
}
|
452
|
+
|
453
|
+
/***********************************************************************
|
454
|
+
* tr_peerIsConnected
|
455
|
+
***********************************************************************
|
456
|
+
*
|
457
|
+
**********************************************************************/
|
458
|
+
int tr_peerIsConnected( tr_peer_t * peer )
|
459
|
+
{
|
460
|
+
return peer->status & PEER_STATUS_CONNECTED;
|
461
|
+
}
|
462
|
+
|
463
|
+
/***********************************************************************
|
464
|
+
* tr_peerIsUploading
|
465
|
+
***********************************************************************
|
466
|
+
*
|
467
|
+
**********************************************************************/
|
468
|
+
int tr_peerIsUploading( tr_peer_t * peer )
|
469
|
+
{
|
470
|
+
return ( peer->inRequestCount > 0 );
|
471
|
+
}
|
472
|
+
|
473
|
+
/***********************************************************************
|
474
|
+
* tr_peerIsDownloading
|
475
|
+
***********************************************************************
|
476
|
+
*
|
477
|
+
**********************************************************************/
|
478
|
+
int tr_peerIsDownloading( tr_peer_t * peer )
|
479
|
+
{
|
480
|
+
return peer->outBlockSending;
|
481
|
+
}
|
482
|
+
|
483
|
+
/***********************************************************************
|
484
|
+
* tr_peerBitfield
|
485
|
+
***********************************************************************
|
486
|
+
*
|
487
|
+
**********************************************************************/
|
488
|
+
uint8_t * tr_peerBitfield( tr_peer_t * peer )
|
489
|
+
{
|
490
|
+
return peer->bitfield;
|
491
|
+
}
|
492
|
+
|
493
|
+
float tr_peerDownloadRate( tr_peer_t * peer )
|
494
|
+
{
|
495
|
+
return tr_rcRate( peer->download );
|
496
|
+
}
|
497
|
+
|
498
|
+
int tr_peerIsUnchoked( tr_peer_t * peer )
|
499
|
+
{
|
500
|
+
return !peer->amChoking;
|
501
|
+
}
|
502
|
+
|
503
|
+
int tr_peerIsInterested ( tr_peer_t * peer )
|
504
|
+
{
|
505
|
+
return peer->peerInterested;
|
506
|
+
}
|
507
|
+
|
508
|
+
void tr_peerChoke( tr_peer_t * peer )
|
509
|
+
{
|
510
|
+
sendChoke( peer, 1 );
|
511
|
+
peer->lastChoke = tr_date();
|
512
|
+
}
|
513
|
+
|
514
|
+
void tr_peerUnchoke( tr_peer_t * peer )
|
515
|
+
{
|
516
|
+
sendChoke( peer, 0 );
|
517
|
+
peer->lastChoke = tr_date();
|
518
|
+
}
|
519
|
+
|
520
|
+
uint64_t tr_peerLastChoke( tr_peer_t * peer )
|
521
|
+
{
|
522
|
+
return peer->lastChoke;
|
523
|
+
}
|
524
|
+
|
525
|
+
void tr_peerSetOptimistic( tr_peer_t * peer, int o )
|
526
|
+
{
|
527
|
+
peer->optimistic = o;
|
528
|
+
}
|
529
|
+
|
530
|
+
int tr_peerIsOptimistic( tr_peer_t * peer )
|
531
|
+
{
|
532
|
+
return peer->optimistic;
|
533
|
+
}
|
534
|
+
|
535
|
+
static inline int peerIsBad( tr_peer_t * peer )
|
536
|
+
{
|
537
|
+
return ( peer->badPcs > 4 + 2 * peer->goodPcs );
|
538
|
+
}
|
539
|
+
|
540
|
+
static inline int peerIsGood( tr_peer_t * peer )
|
541
|
+
{
|
542
|
+
return ( peer->goodPcs > 3 * peer->badPcs );
|
543
|
+
}
|
544
|
+
|
545
|
+
void tr_peerBlame( tr_torrent_t * tor, tr_peer_t * peer,
|
546
|
+
int piece, int success )
|
547
|
+
{
|
548
|
+
if( !peer->blamefield || !tr_bitfieldHas( peer->blamefield, piece ) )
|
549
|
+
{
|
550
|
+
return;
|
551
|
+
}
|
552
|
+
|
553
|
+
if( success )
|
554
|
+
{
|
555
|
+
peer->goodPcs++;
|
556
|
+
|
557
|
+
if( peer->banfield && peerIsGood( peer ) )
|
558
|
+
{
|
559
|
+
/* Assume the peer wasn't responsible for the bad pieces
|
560
|
+
we was banned for */
|
561
|
+
memset( peer->banfield, 0x00, ( tor->info.pieceCount + 7 ) / 8 );
|
562
|
+
}
|
563
|
+
}
|
564
|
+
else
|
565
|
+
{
|
566
|
+
peer->badPcs++;
|
567
|
+
|
568
|
+
/* Ban the peer for this piece */
|
569
|
+
if( !peer->banfield )
|
570
|
+
{
|
571
|
+
peer->banfield = calloc( ( tor->info.pieceCount + 7 ) / 8, 1 );
|
572
|
+
}
|
573
|
+
tr_bitfieldAdd( peer->banfield, piece );
|
574
|
+
|
575
|
+
if( peerIsBad( peer ) )
|
576
|
+
{
|
577
|
+
/* Full ban */
|
578
|
+
peer_dbg( "banned (%d / %d)", peer->goodPcs, peer->badPcs );
|
579
|
+
peer->banned = 1;
|
580
|
+
peer->peerInterested = 0;
|
581
|
+
}
|
582
|
+
}
|
583
|
+
tr_bitfieldRem( peer->blamefield, piece );
|
584
|
+
}
|