transmission 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }