2
* This file Copyright (C) 2007-2008 Charles Kerr <charles@rebelbase.com>
2
* This file Copyright (C) 2007-2009 Charles Kerr <charles@transmissionbt.com>
4
4
* This file is licensed by the GPL version 2. Works owned by the
5
5
* Transmission project are granted a special exemption to clause 2(b)
6
* so that the bulk of its code can remain under the MIT license.
6
* so that the bulk of its code can remain under the MIT license.
7
7
* This exemption does not extend to derived works not owned by
8
8
* the Transmission project.
10
* $Id: tracker.c 5881 2008-05-21 17:25:56Z charles $
10
* $Id: tracker.c 8268 2009-04-21 16:52:28Z charles $
13
13
#include <assert.h>
14
#include <stdio.h> /* snprintf */
15
14
#include <stdlib.h>
16
15
#include <string.h> /* strcmp, strchr */
20
19
#include "transmission.h"
21
21
#include "bencode.h"
22
23
#include "completion.h"
24
#include "port-forwarding.h"
25
25
#include "publish.h"
26
27
#include "torrent.h"
27
28
#include "tracker.h"
28
#include "trcompat.h" /* strlcpy */
29
29
#include "trevent.h"
35
/* the announceAt fields are set to this when the action is disabled */
36
TR_TRACKER_STOPPED = 0,
38
/* the announceAt fields are set to this when the action is in progress */
37
43
/* seconds between tracker pulses */
38
44
PULSE_INTERVAL_MSEC = 1000,
40
/* maximum number of concurrent tracker socket connections */
41
MAX_TRACKER_SOCKETS = 16,
43
/* maximum number of concurrent tracker socket connections during shutdown.
44
* all the peer connections should be gone by now, so we can hog more
45
* connections to send `stop' messages to the trackers */
46
MAX_TRACKER_SOCKETS_DURING_SHUTDOWN = 64,
48
46
/* unless the tracker says otherwise, rescrape this frequently */
49
DEFAULT_SCRAPE_INTERVAL_SEC = (60 * 15),
47
DEFAULT_SCRAPE_INTERVAL_SEC = ( 60 * 15 ),
51
49
/* unless the tracker says otherwise, this is the announce interval */
52
DEFAULT_ANNOUNCE_INTERVAL_SEC = (60 * 4),
50
DEFAULT_ANNOUNCE_INTERVAL_SEC = ( 60 * 4 ),
54
52
/* unless the tracker says otherwise, this is the announce min_interval */
55
DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC = (60 * 2),
53
DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC = ( 60 * 2 ),
55
/* how long to wait before a rescrape the first time we get an error */
56
FIRST_SCRAPE_RETRY_INTERVAL_SEC = 30,
58
/* how long to wait before a reannounce the first time we get an error */
59
FIRST_ANNOUNCE_RETRY_INTERVAL_SEC = 30,
57
61
/* the value of the 'numwant' argument passed in tracker requests. */
60
64
/* the length of the 'key' argument passed in tracker requests */
70
unsigned int isRunning : 1;
76
/* these are set from the latest scrape or tracker response */
77
int announceIntervalSec;
78
int announceMinIntervalSec;
79
int scrapeIntervalSec;
80
int retryScrapeIntervalSec;
82
/* index into the torrent's tr_info.trackers array */
85
78
/* sent as the "key" argument in tracker requests
86
79
to verify us if our IP address changes.
87
80
This is immutable for the life of the tracker object. */
88
char key_param[KEYLEN+1];
90
tr_publisher_t * publisher;
81
char key_param[KEYLEN + 1];
83
/* these are set from the latest scrape or tracker response */
84
int announceIntervalSec;
85
int announceMinIntervalSec;
86
int scrapeIntervalSec;
87
int retryScrapeIntervalSec;
88
int retryAnnounceIntervalSec;
90
/* index into the torrent's tr_info.trackers array */
95
tr_publisher publisher;
92
97
/* torrent hash string */
93
uint8_t hash[SHA_DIGEST_LENGTH];
94
char escaped[SHA_DIGEST_LENGTH*3 + 1];
98
uint8_t hash[SHA_DIGEST_LENGTH];
99
char escaped[SHA_DIGEST_LENGTH * 3 + 1];
97
103
/* corresponds to the peer_id sent as a tracker request parameter.
98
104
one tracker admin says: "When the same torrent is opened and
99
105
closed and opened again without quitting Transmission ...
100
106
change the peerid. It would help sometimes if a stopped event
101
107
was missed to ensure that we didn't think someone was cheating. */
104
110
/* these are set from the latest tracker response... -1 is 'unknown' */
110
time_t manualAnnounceAllowedAt;
114
time_t lastScrapeTime;
115
long lastScrapeResponse;
117
time_t lastAnnounceTime;
118
long lastAnnounceResponse;
117
time_t manualAnnounceAllowedAt;
120
/* 0==never, 1==in progress, other values==when to scrape */
123
time_t lastScrapeTime;
124
long lastScrapeResponse;
126
time_t lastAnnounceTime;
127
long lastAnnounceResponse;
121
#define dbgmsg(name, fmt...) tr_deepLog(__FILE__, __LINE__, name, ##fmt )
130
#define dbgmsg( name, ... ) \
132
if( tr_deepLoggingIsActive( ) ) \
133
tr_deepLog( __FILE__, __LINE__, name, __VA_ARGS__ ); \
127
140
static const tr_tracker_info *
128
getCurrentAddressFromTorrent( const tr_tracker * t, const tr_torrent * tor )
141
getCurrentAddressFromTorrent( tr_tracker * t,
142
const tr_torrent * tor )
144
/* user might have removed trackers,
145
* so check to make sure our current index is in-bounds */
146
if( t->trackerIndex >= tor->info.trackerCount )
130
149
assert( t->trackerIndex >= 0 );
131
150
assert( t->trackerIndex < tor->info.trackerCount );
132
151
return tor->info.trackers + t->trackerIndex;
135
154
static const tr_tracker_info *
136
getCurrentAddress( const tr_tracker * t )
155
getCurrentAddress( tr_tracker * t )
138
157
const tr_torrent * torrent;
139
if(( torrent = tr_torrentFindFromHash( t->session, t->hash )))
159
if( ( torrent = tr_torrentFindFromId( t->session, t->torrentId ) ) )
140
160
return getCurrentAddressFromTorrent( t, torrent );
145
trackerSupportsScrape( const tr_tracker * t, const tr_torrent * tor )
165
trackerSupportsScrape( tr_tracker * t,
166
const tr_torrent * tor )
147
168
const tr_tracker_info * info = getCurrentAddressFromTorrent( t, tor );
148
170
return info && info->scrape;
188
publishErrorMessageAndStop( tr_tracker * t, const char * msg )
212
publishErrorMessageAndStop( tr_tracker * t,
190
215
t->isRunning = 0;
191
216
publishMessage( t, msg, TR_TRACKER_ERROR );
195
publishWarning( tr_tracker * t, const char * msg )
220
publishWarning( tr_tracker * t,
197
223
publishMessage( t, msg, TR_TRACKER_WARNING );
201
publishNewPeers( tr_tracker * t, int allAreSeeds,
202
void * compact, int compactLen )
227
publishNewPeers( tr_tracker * t,
204
232
tr_tracker_event event = emptyEvent;
205
event.hash = t->hash;
206
234
event.messageType = TR_TRACKER_PEERS;
207
235
event.allAreSeeds = allAreSeeds;
208
236
event.compact = compact;
209
237
event.compactLen = compactLen;
211
tr_publisherPublish( t->publisher, t, &event );
239
tr_publisherPublish( &t->publisher, t, &event );
243
publishNewPeersCompact( tr_tracker * t,
249
uint8_t *array, *walk, *compactWalk;
250
const int peerCount = compactLen / 6;
251
const int arrayLen = peerCount * ( sizeof( tr_address ) + 2 );
255
addr.type = TR_AF_INET;
256
memset( &addr.addr, 0x00, sizeof( addr.addr ) );
257
array = tr_new( uint8_t, arrayLen );
258
for ( i = 0, walk = array, compactWalk = compact ; i < peerCount ; i++ )
260
memcpy( &addr.addr.addr4, compactWalk, 4 );
261
memcpy( &port, compactWalk + 4, 2 );
263
memcpy( walk, &addr, sizeof( addr ) );
264
memcpy( walk + sizeof( addr ), &port, 2 );
266
walk += sizeof( tr_address ) + 2;
269
publishNewPeers( t, allAreSeeds, array, arrayLen );
274
publishNewPeersCompact6( tr_tracker * t,
280
uint8_t *array, *walk, *compactWalk;
281
const int peerCount = compactLen / 18;
282
const int arrayLen = peerCount * ( sizeof( tr_address ) + 2 );
286
addr.type = TR_AF_INET6;
287
memset( &addr.addr, 0x00, sizeof( addr.addr ) );
288
array = tr_new( uint8_t, arrayLen );
289
for ( i = 0, walk = array, compactWalk = compact ; i < peerCount ; i++ )
291
memcpy( &addr.addr.addr6, compactWalk, 16 );
292
memcpy( &port, compactWalk + 16, 2 );
295
memcpy( walk, &addr, sizeof( addr ) );
296
memcpy( walk + sizeof( addr ), &port, 2 );
297
walk += sizeof( tr_address ) + 2;
299
publishNewPeers( t, allAreSeeds, array, arrayLen );
249
/* Convert to compact form */
251
parseOldPeers( tr_benc * bePeers, size_t * byteCount )
340
parseOldPeers( tr_benc * bePeers,
254
uint8_t *compact, *walk;
344
uint8_t * array, *walk;
255
345
const int peerCount = bePeers->val.l.count;
257
assert( bePeers->type == TYPE_LIST );
259
compact = tr_new( uint8_t, peerCount*6 );
261
for( i=0, walk=compact; i<peerCount; ++i )
347
assert( tr_bencIsList( bePeers ) );
349
array = tr_new( uint8_t, peerCount * ( sizeof( tr_address ) + 2 ) );
351
for( i = 0, walk = array; i < peerCount; ++i )
267
tr_benc * peer = &bePeers->val.l.vals[i];
269
if( !tr_bencDictFindStr( peer, "ip", &s ) || tr_netResolve( s, &addr ) )
272
memcpy( walk, &addr, 4 );
275
if( !tr_bencDictFindInt( peer, "port", &itmp ) || itmp<0 || itmp>0xffff )
357
tr_benc * peer = &bePeers->val.l.vals[i];
359
if( tr_bencDictFindStr( peer, "ip", &s ) )
361
if( tr_pton( s, &addr ) == NULL )
364
if( !tr_bencDictFindInt( peer, "port",
365
&itmp ) || itmp < 0 || itmp > 0xffff )
368
memcpy( walk, &addr, sizeof( tr_address ) );
278
369
port = htons( itmp );
279
memcpy( walk, &port, 2 );
370
memcpy( walk + sizeof( tr_address ), &port, 2 );
371
walk += sizeof( tr_address ) + 2;
283
*byteCount = peerCount * 6;
374
*byteCount = peerCount * sizeof( tr_address ) + 2;
288
379
onStoppedResponse( tr_session * session,
289
long responseCode UNUSED,
290
const void * response UNUSED,
291
size_t responseLen UNUSED,
292
void * torrent_hash )
380
long responseCode UNUSED,
381
const void * response UNUSED,
382
size_t responseLen UNUSED,
385
tr_tracker * t = findTracker( session, tr_ptr2int( torrentId ) );
388
const time_t now = time( NULL );
390
t->reannounceAt = TR_TRACKER_STOPPED;
391
t->manualAnnounceAllowedAt = TR_TRACKER_STOPPED;
393
if( t->scrapeAt <= now )
394
t->scrapeAt = now + t->scrapeIntervalSec + t->randOffset;
294
397
dbgmsg( NULL, "got a response to some `stop' message" );
295
tr_free( torrent_hash );
296
398
onReqDone( session );
300
onTrackerResponse( tr_session * session,
302
const void * response,
304
void * torrent_hash )
402
onTrackerResponse( tr_session * session,
404
const void * response,
307
409
int success = FALSE;
410
int scrapeFields = 0;
310
413
onReqDone( session );
311
t = findTracker( session, torrent_hash );
312
tr_free( torrent_hash );
414
t = findTracker( session, tr_ptr2int( torrentId ) );
313
415
if( !t ) /* tracker's been closed */
316
dbgmsg( t->name, "tracker response: %d", responseCode );
317
tr_ndbg( t->name, "tracker response: %d", responseCode );
418
dbgmsg( t->name, "tracker response: %ld", responseCode );
419
tr_ndbg( t->name, "tracker response: %ld", responseCode );
318
420
t->lastAnnounceResponse = responseCode;
320
422
if( responseCode == HTTP_OK )
323
const int bencLoaded = !tr_bencLoad( response, responseLen, &benc, 0 );
425
const int bencLoaded = !tr_bencLoad( response, responseLen,
324
427
publishErrorClear( t );
325
428
if( bencLoaded && tr_bencIsDict( &benc ) )
330
433
const char * str;
436
t->retryAnnounceIntervalSec = FIRST_SCRAPE_RETRY_INTERVAL_SEC;
334
if(( tr_bencDictFindStr( &benc, "failure reason", &str ))) {
335
// publishErrorMessageAndStop( t, str );
438
if( ( tr_bencDictFindStr( &benc, "failure reason", &str ) ) )
336
440
publishMessage( t, str, TR_TRACKER_ERROR );
340
if(( tr_bencDictFindStr( &benc, "warning message", &str )))
444
if( ( tr_bencDictFindStr( &benc, "warning message", &str ) ) )
341
445
publishWarning( t, str );
343
if(( tr_bencDictFindInt( &benc, "interval", &i ))) {
447
if( ( tr_bencDictFindInt( &benc, "interval", &i ) ) )
344
449
dbgmsg( t->name, "setting interval to %d", (int)i );
345
450
t->announceIntervalSec = i;
348
if(( tr_bencDictFindInt( &benc, "min interval", &i ))) {
453
if( ( tr_bencDictFindInt( &benc, "min interval", &i ) ) )
349
455
dbgmsg( t->name, "setting min interval to %d", (int)i );
350
456
t->announceMinIntervalSec = i;
353
if(( tr_bencDictFindStr( &benc, "tracker id", &str )))
459
if( ( tr_bencDictFindStr( &benc, "tracker id", &str ) ) )
354
460
t->trackerID = tr_strdup( str );
356
if(( tr_bencDictFindInt( &benc, "complete", &i )))
462
if( ( tr_bencDictFindInt( &benc, "complete", &i ) ) )
357
465
t->seederCount = i;
359
if(( tr_bencDictFindInt( &benc, "incomplete", &i )))
468
if( ( tr_bencDictFindInt( &benc, "incomplete", &i ) ) )
360
471
t->leecherCount = incomplete = i;
362
if(( tmp = tr_bencDictFind( &benc, "peers" )))
364
const int allAreSeeds = incomplete == 0;
366
if( tmp->type == TYPE_STR ) /* "compact" extension */
368
publishNewPeers( t, allAreSeeds, tmp->val.s.s, tmp->val.s.i );
370
else if( tmp->type == TYPE_LIST ) /* original protocol */
372
size_t byteCount = 0;
373
uint8_t * compact = parseOldPeers( tmp, &byteCount );
374
publishNewPeers( t, allAreSeeds, compact, byteCount );
474
if( ( tr_bencDictFindInt( &benc, "downloaded", &i ) ) )
477
t->timesDownloaded = i;
480
if( ( tmp = tr_bencDictFind( &benc, "peers" ) ) )
482
const int allAreSeeds = incomplete == 0;
484
if( tr_bencIsString( tmp ) ) /* "compact" extension */
486
publishNewPeersCompact( t, allAreSeeds, tmp->val.s.s,
489
else if( tr_bencIsList( tmp ) ) /* original protocol */
491
size_t byteCount = 0;
492
uint8_t * array = parseOldPeers( tmp, &byteCount );
493
publishNewPeers( t, allAreSeeds, array, byteCount );
498
if( ( tmp = tr_bencDictFind( &benc, "peers6" ) ) )
500
const int allAreSeeds = incomplete == 0;
502
if( tr_bencIsString( tmp ) ) /* "compact" extension */
504
publishNewPeersCompact6( t, allAreSeeds, tmp->val.s.s,
381
511
tr_bencFree( &benc );
513
else if( responseCode )
515
/* %1$ld - http status code, such as 404
516
* %2$s - human-readable explanation of the http status code */
517
char * buf = tr_strdup_printf( _( "Tracker request failed. Got HTTP Status Code %1$ld (%2$s)" ),
519
tr_webGetResponseStr( responseCode ) );
520
publishWarning( t, buf );
384
524
retry = updateAddresses( t, success );
526
if( responseCode && retry )
391
527
responseCode = 300;
393
if( 200<=responseCode && responseCode<=299 )
395
const int interval = t->announceIntervalSec + t->randOffset;
529
if( responseCode == 0 )
531
dbgmsg( t->name, "No response from tracker... retrying in two minutes." );
532
t->manualAnnounceAllowedAt = ~(time_t)0;
533
t->reannounceAt = time( NULL ) + t->randOffset + 120;
535
else if( 200 <= responseCode && responseCode <= 299 )
537
const int interval = t->announceIntervalSec + t->randOffset;
396
538
const time_t now = time ( NULL );
397
539
dbgmsg( t->name, "request succeeded. reannouncing in %d seconds", interval );
398
t->scrapeAt = now + t->scrapeIntervalSec + t->randOffset;
541
/* if the announce response was a superset of the scrape response,
542
treat this as both a successful announce AND scrape. */
543
if( scrapeFields >= 3 ) {
544
t->lastScrapeResponse = responseCode;
545
t->lastScrapeTime = now;
546
t->scrapeAt = now + t->scrapeIntervalSec + t->randOffset;
549
/* most trackers don't provide all the scrape responses, but do
550
provide most of them, so don't scrape too soon anyway */
551
if( ( scrapeFields == 2 ) && ( t->scrapeAt <= ( now + 120 ) ) ) {
552
t->scrapeAt = now + t->scrapeIntervalSec + t->randOffset;
399
555
t->reannounceAt = now + interval;
400
556
t->manualAnnounceAllowedAt = now + t->announceMinIntervalSec;
558
/* #319: save the .resume file after an announce so that, in case
559
* of a crash, our stats still match up with the tracker's stats */
560
tr_torrentSaveResume( tr_torrentFindFromHash( t->session, t->hash ) );
402
else if( 300<=responseCode && responseCode<=399 )
562
else if( 300 <= responseCode && responseCode <= 399 )
404
564
/* it's a redirect... updateAddresses() has already
405
565
* parsed the redirect, all that's left is to retry */
439
onScrapeResponse( tr_session * session,
441
const void * response,
443
void * torrent_hash )
600
onScrapeResponse( tr_session * session,
602
const void * response,
449
610
onReqDone( session );
450
t = findTracker( session, torrent_hash );
451
tr_free( torrent_hash );
611
t = findTracker( session, tr_ptr2int( torrentId ) );
452
612
if( !t ) /* tracker's been closed... */
455
615
dbgmsg( t->name, "scrape response: %ld\n", responseCode );
456
tr_ndbg( t->name, "scrape response: %d", responseCode );
616
tr_ndbg( t->name, "scrape response: %ld", responseCode );
457
617
t->lastScrapeResponse = responseCode;
459
619
if( responseCode == HTTP_OK )
461
tr_benc benc, *files;
462
const int bencLoaded = !tr_bencLoad( response, responseLen, &benc, 0 );
621
tr_benc benc, *files;
622
const int bencLoaded = !tr_bencLoad( response, responseLen,
463
624
if( bencLoaded && tr_bencDictFindDict( &benc, "files", &files ) )
466
for( i=0; i<files->val.l.count; i+=2 )
627
for( i = 0; i < files->val.l.count; i += 2 )
469
630
const uint8_t* hash =
470
631
(const uint8_t*) files->val.l.vals[i].val.s.s;
472
tr_benc * tordict = &files->val.l.vals[i+1];
633
tr_benc * tordict = &files->val.l.vals[i + 1];
473
634
if( memcmp( t->hash, hash, SHA_DIGEST_LENGTH ) )
476
637
publishErrorClear( t );
478
if(( tr_bencDictFindInt( tordict, "complete", &itmp )))
639
if( ( tr_bencDictFindInt( tordict, "complete", &itmp ) ) )
479
640
t->seederCount = itmp;
481
if(( tr_bencDictFindInt( tordict, "incomplete", &itmp )))
642
if( ( tr_bencDictFindInt( tordict, "incomplete", &itmp ) ) )
482
643
t->leecherCount = itmp;
484
if(( tr_bencDictFindInt( tordict, "downloaded", &itmp )))
645
if( ( tr_bencDictFindInt( tordict, "downloaded", &itmp ) ) )
485
646
t->timesDownloaded = itmp;
487
if( tr_bencDictFindDict( tordict, "flags", &flags ))
488
if(( tr_bencDictFindInt( flags, "min_request_interval", &itmp )))
648
if( ( tr_bencDictFindInt( tordict, "downloaders", &itmp ) ) )
649
t->downloaderCount = itmp;
651
if( tr_bencDictFindDict( tordict, "flags", &flags ) )
652
if( ( tr_bencDictFindInt( flags, "min_request_interval", &itmp ) ) )
489
653
t->scrapeIntervalSec = i;
655
/* as per ticket #1045, safeguard against trackers returning
656
* a very low min_request_interval... */
657
if( t->scrapeIntervalSec < DEFAULT_SCRAPE_INTERVAL_SEC )
658
t->scrapeIntervalSec = DEFAULT_SCRAPE_INTERVAL_SEC;
661
"Scrape successful. Rescraping in %d seconds.",
662
t->scrapeIntervalSec );
493
tr_ndbg( t->name, "Scrape successful. Rescraping in %d seconds.",
494
t->scrapeIntervalSec );
496
t->retryScrapeIntervalSec = 30;
665
t->retryScrapeIntervalSec = FIRST_SCRAPE_RETRY_INTERVAL_SEC;
511
680
responseCode = 300;
513
if( 200<=responseCode && responseCode<=299 )
682
if( 200 <= responseCode && responseCode <= 299 )
515
684
const int interval = t->scrapeIntervalSec + t->randOffset;
516
dbgmsg( t->name, "request succeeded. rescraping in %d seconds", interval );
517
tr_ndbg( t->name, "request succeeded. rescraping in %d seconds", interval );
685
dbgmsg( t->name, "Request succeeded. Rescraping in %d seconds",
687
tr_ndbg( t->name, "Request succeeded. Rescraping in %d seconds",
518
689
t->scrapeAt = time( NULL ) + interval;
520
else if( 300<=responseCode && responseCode<=399 )
691
else if( 300 <= responseCode && responseCode <= 399 )
522
693
const int interval = 5;
523
dbgmsg( t->name, "got a redirect. retrying in %d seconds", interval );
694
dbgmsg( t->name, "Got a redirect. Retrying in %d seconds", interval );
524
695
t->scrapeAt = time( NULL ) + interval;
528
699
const int interval = t->retryScrapeIntervalSec + t->randOffset;
529
dbgmsg( t->name, "Tracker responded to scrape with %d. Retrying in %d seconds.",
530
responseCode, interval );
702
"Tracker responded to scrape with %ld. Retrying in %d seconds.",
703
responseCode, interval );
531
704
t->retryScrapeIntervalSec *= 2;
532
705
t->scrapeAt = time( NULL ) + interval;
543
716
TR_REQ_COMPLETED,
718
TR_REQ_PAUSED, /* BEP 21 */
545
719
TR_REQ_REANNOUNCE,
550
724
struct tr_tracker_request
553
int reqtype; /* TR_REQ_* */
554
uint8_t torrent_hash[SHA_DIGEST_LENGTH];
555
tr_web_done_func * done_func;
556
tr_session * session;
726
int reqtype; /* TR_REQ_* */
728
struct evbuffer * url;
729
tr_web_done_func * done_func;
730
tr_session * session;
560
734
freeRequest( struct tr_tracker_request * req )
736
evbuffer_free( req->url );
567
buildTrackerRequestURI( const tr_tracker * t,
568
const tr_torrent * torrent,
569
const char * eventName,
570
struct evbuffer * buf )
741
buildTrackerRequestURI( tr_tracker * t,
742
const tr_torrent * torrent,
743
const char * eventName,
744
struct evbuffer * buf )
572
const int isStopping = !strcmp( eventName, "stopped" );
573
const int numwant = isStopping ? 0 : NUMWANT;
574
const char * ann = getCurrentAddressFromTorrent(t,torrent)->announce;
746
const int isStopping = !strcmp( eventName, "stopped" );
747
const int numwant = isStopping ? 0 : NUMWANT;
748
const char * ann = getCurrentAddressFromTorrent( t, torrent )->announce;
576
750
evbuffer_add_printf( buf, "%cinfo_hash=%s"
580
"&downloaded=%"PRIu64
754
"&downloaded=%" PRIu64
588
strchr(ann, '?') ? '&' : '?',
591
tr_sharedGetPublicPort( t->session->shared ),
592
torrent->uploadedCur,
593
torrent->downloadedCur,
595
tr_cpLeftUntilComplete( torrent->completion ),
598
( ( eventName && *eventName ) ? "&event=" : "" ),
599
( ( eventName && *eventName ) ? eventName : "" ),
600
( ( t->trackerID && *t->trackerID ) ? "&trackerid=" : "" ),
601
( ( t->trackerID && *t->trackerID ) ? t->trackerID : "" ) );
760
strchr( ann, '?' ) ? '&' : '?',
763
tr_sessionGetPeerPort( t->session ),
764
torrent->uploadedCur,
765
torrent->downloadedCur,
767
tr_cpLeftUntilComplete( &torrent->completion ),
771
if( eventName && *eventName )
772
evbuffer_add_printf( buf, "&event=%s", eventName );
774
if( t->trackerID && *t->trackerID )
775
evbuffer_add_printf( buf, "&trackerid=%s", t->trackerID );
604
779
static struct tr_tracker_request*
605
createRequest( tr_session * session, const tr_tracker * tracker, int reqtype )
780
createRequest( tr_session * session,
781
tr_tracker * tracker,
607
static const char* strings[] = { "started", "completed", "stopped", "", "err" };
784
static const char* strings[] = { "started", "completed", "stopped", "paused", "", "err" };
608
785
const tr_torrent * torrent = tr_torrentFindFromHash( session, tracker->hash );
609
786
const tr_tracker_info * address = getCurrentAddressFromTorrent( tracker, torrent );
610
const int isStopping = reqtype == TR_REQ_STOPPED;
611
788
struct tr_tracker_request * req;
612
789
struct evbuffer * url;
791
/* BEP 21: In order to tell the tracker that a peer is a partial seed, it MUST send
792
* an event=paused parameter in every announce while it is a partial seed. */
793
if( tr_cpGetStatus( &torrent->completion ) == TR_PARTIAL_SEED )
794
reqtype = TR_REQ_PAUSED;
796
isStopping = reqtype == TR_REQ_STOPPED;
614
798
url = evbuffer_new( );
615
799
evbuffer_add_printf( url, "%s", address->announce );
616
800
buildTrackerRequestURI( tracker, torrent, strings[reqtype], url );
619
803
req->session = session;
620
804
req->reqtype = reqtype;
621
805
req->done_func = isStopping ? onStoppedResponse : onTrackerResponse;
622
req->url = tr_strdup( ( char * ) EVBUFFER_DATA( url ) );
623
memcpy( req->torrent_hash, tracker->hash, SHA_DIGEST_LENGTH );
807
req->torrentId = tracker->torrentId;
625
evbuffer_free( url );
629
812
static struct tr_tracker_request*
630
createScrape( tr_session * session, const tr_tracker * tracker )
813
createScrape( tr_session * session,
814
tr_tracker * tracker )
632
const tr_tracker_info * a = getCurrentAddress( tracker );
816
const tr_tracker_info * a = getCurrentAddress( tracker );
633
817
struct tr_tracker_request * req;
634
struct evbuffer * url = evbuffer_new( );
818
struct evbuffer * url = evbuffer_new( );
636
820
evbuffer_add_printf( url, "%s%cinfo_hash=%s",
637
a->scrape, strchr(a->scrape,'?')?'&':'?',
821
a->scrape, strchr( a->scrape, '?' ) ? '&' : '?',
640
824
req = tr_new0( struct tr_tracker_request, 1 );
641
825
req->session = session;
642
826
req->reqtype = TR_REQ_SCRAPE;
643
req->url = tr_strdup( ( char * ) EVBUFFER_DATA( url ) );
644
828
req->done_func = onScrapeResponse;
645
memcpy( req->torrent_hash, tracker->hash, SHA_DIGEST_LENGTH );
829
req->torrentId = tracker->torrentId;
647
evbuffer_free( url );
651
834
struct tr_tracker_handle
653
unsigned int isShuttingDown : 1;
655
tr_timer * pulseTimer;
836
tr_bool shutdownHint;
838
tr_timer * pulseTimer;
658
static int pulse( void * vsession );
841
static int trackerPulse( void * vsession );
844
tr_trackerSessionInit( tr_session * session )
846
assert( tr_isSession( session ) );
848
session->tracker = tr_new0( struct tr_tracker_handle, 1 );
849
session->tracker->pulseTimer = tr_timerNew( session, trackerPulse, session, PULSE_INTERVAL_MSEC );
850
dbgmsg( NULL, "creating tracker timer" );
854
tr_trackerSessionClose( tr_session * session )
856
assert( tr_isSession( session ) );
858
session->tracker->shutdownHint = TRUE;
661
ensureGlobalsExist( tr_session * session )
663
if( session->tracker == NULL )
665
session->tracker = tr_new0( struct tr_tracker_handle, 1 );
666
session->tracker->pulseTimer = tr_timerNew( session, pulse, session, PULSE_INTERVAL_MSEC );
667
dbgmsg( NULL, "creating tracker timer" );
672
tr_trackerShuttingDown( tr_session * session )
674
if( session->tracker )
675
session->tracker->isShuttingDown = 1;
679
maybeFreeGlobals( tr_session * session )
681
int globalsExist = session->tracker != NULL;
684
&& ( session->tracker->runningCount < 1 )
685
&& ( session->torrentList== NULL ) )
862
tr_trackerSessionDestroy( tr_session * session )
864
if( session && session->tracker )
687
866
dbgmsg( NULL, "freeing tracker timer" );
688
867
tr_timerFree( &session->tracker->pulseTimer );
689
868
tr_free( session->tracker );
690
869
session->tracker = NULL;
691
globalsExist = FALSE;
702
878
invokeRequest( void * vreq )
704
880
struct tr_tracker_request * req = vreq;
706
tr_tracker * t = findTracker( req->session, req->torrent_hash );
883
assert( req != NULL );
884
assert( tr_isSession( req->session ) );
885
assert( req->torrentId >= 0 );
886
assert( req->reqtype >= 0 );
887
assert( req->reqtype < TR_NUM_REQ_TYPES );
889
dbgmsg( NULL, "invokeRequest got session %p, tracker %p", req->session, req->session->tracker );
891
t = findTracker( req->session, req->torrentId );
710
895
const time_t now = time( NULL );
712
897
if( req->reqtype == TR_REQ_SCRAPE )
714
899
t->lastScrapeTime = now;
900
t->scrapeAt = TR_TRACKER_BUSY;
719
904
t->lastAnnounceTime = now;
721
t->scrapeAt = req->reqtype == TR_REQ_STOPPED
722
? now + t->scrapeIntervalSec + t->randOffset
905
t->reannounceAt = TR_TRACKER_BUSY;
906
t->manualAnnounceAllowedAt = TR_TRACKER_BUSY;
910
assert( req->session->tracker != NULL );
727
911
++req->session->tracker->runningCount;
729
hash = tr_new0( uint8_t, SHA_DIGEST_LENGTH );
730
memcpy( hash, req->torrent_hash, SHA_DIGEST_LENGTH );
731
tr_webRun( req->session, req->url, req->done_func, hash );
913
tr_webRun( req->session,
914
(char*)EVBUFFER_DATA(req->url),
916
req->done_func, tr_int2ptr( req->torrentId ) );
733
918
freeRequest( req );
736
static void ensureGlobalsExist( tr_session * );
739
enqueueScrape( tr_session * session, const tr_tracker * tracker )
922
enqueueScrape( tr_session * session,
923
tr_tracker * tracker )
741
925
struct tr_tracker_request * req;
742
ensureGlobalsExist( session );
926
assert( tr_isSession( session ) );
743
928
req = createScrape( session, tracker );
744
929
tr_runInEventThread( session, invokeRequest, req );
748
enqueueRequest( tr_session * session, const tr_tracker * tracker, int reqtype )
933
enqueueRequest( tr_session * session,
934
tr_tracker * tracker,
750
937
struct tr_tracker_request * req;
751
ensureGlobalsExist( session );
938
assert( tr_isSession( session ) );
752
940
req = createRequest( session, tracker, reqtype );
753
941
tr_runInEventThread( session, invokeRequest, req );
757
pulse( void * vsession )
945
trackerPulse( void * vsession )
759
tr_session * session = vsession;
947
tr_session * session = vsession;
760
948
struct tr_tracker_handle * th = session->tracker;
762
const time_t now = time( NULL );
950
const time_t now = time( NULL );
764
if( !session->tracker )
767
955
if( th->runningCount )
768
956
dbgmsg( NULL, "tracker pulse... %d running", th->runningCount );
770
958
/* upkeep: queue periodic rescrape / reannounce */
771
for( tor=session->torrentList; tor; tor=tor->next )
960
while(( tor = tr_torrentNext( session, tor )))
773
962
tr_tracker * t = tor->tracker;
775
if( t->scrapeAt && trackerSupportsScrape( t, tor ) && ( now >= t->scrapeAt ) ) {
964
if( ( t->scrapeAt > 1 )
965
&& ( t->scrapeAt <= now )
966
&& ( trackerSupportsScrape( t, tor ) ) )
968
t->scrapeAt = TR_TRACKER_BUSY;
777
969
enqueueScrape( session, t );
780
if( t->reannounceAt && t->isRunning && ( now >= t->reannounceAt ) ) {
972
if( ( t->reannounceAt > 1 )
973
&& ( t->reannounceAt <= now )
974
&& ( t->isRunning ) )
976
t->reannounceAt = TR_TRACKER_BUSY;
977
t->manualAnnounceAllowedAt = TR_TRACKER_BUSY;
782
978
enqueueRequest( session, t, TR_REQ_REANNOUNCE );
786
982
if( th->runningCount )
787
dbgmsg( NULL, "tracker pulse after upkeep... %d running", th->runningCount );
789
return maybeFreeGlobals( session );
983
dbgmsg( NULL, "tracker pulse after upkeep... %d running",
986
/* free the tracker manager if no torrents are left */
988
&& ( th->shutdownHint != FALSE )
989
&& ( th->runningCount < 1 )
990
&& ( tr_sessionCountTorrents( session ) == 0 ) )
992
tr_trackerSessionDestroy( session );
808
generateKeyParam( char * msg, int len )
1016
generateKeyParam( char * msg,
811
1020
const char * pool = "abcdefghijklmnopqrstuvwxyz0123456789";
812
const int poolSize = strlen( pool );
813
for( i=0; i<len; ++i )
814
*msg++ = pool[tr_rand(poolSize)];
1021
const int poolSize = strlen( pool );
1023
for( i = 0; i < len; ++i )
1024
*msg++ = pool[tr_cryptoRandInt( poolSize )];
819
1029
is_rfc2396_alnum( char ch )
821
return ( '0' <= ch && ch <= '9' )
822
|| ( 'A' <= ch && ch <= 'Z' )
823
|| ( 'a' <= ch && ch <= 'z' );
1031
return ( '0' <= ch && ch <= '9' )
1032
|| ( 'A' <= ch && ch <= 'Z' )
1033
|| ( 'a' <= ch && ch <= 'z' );
827
escape( char * out, const uint8_t * in, int in_len ) /* rfc2396 */
1039
int in_len ) /* rfc2396 */
829
1041
const uint8_t *end = in + in_len;
830
1043
while( in != end )
831
if( is_rfc2396_alnum(*in) )
1044
if( is_rfc2396_alnum( *in ) )
832
1045
*out++ = (char) *in++;
834
out += snprintf( out, 4, "%%%02X", (unsigned int)*in++ );
1047
out += tr_snprintf( out, 4, "%%%02X", (unsigned int)*in++ );
839
1053
tr_trackerNew( const tr_torrent * torrent )
841
1055
const tr_info * info = &torrent->info;
844
1058
t = tr_new0( tr_tracker, 1 );
845
t->publisher = tr_publisherNew( );
846
t->session = torrent->handle;
1059
t->publisher = TR_PUBLISHER_INIT;
1060
t->session = torrent->session;
847
1061
t->scrapeIntervalSec = DEFAULT_SCRAPE_INTERVAL_SEC;
848
t->retryScrapeIntervalSec = 60;
1062
t->retryScrapeIntervalSec = FIRST_SCRAPE_RETRY_INTERVAL_SEC;
1063
t->retryAnnounceIntervalSec = FIRST_ANNOUNCE_RETRY_INTERVAL_SEC;
849
1064
t->announceIntervalSec = DEFAULT_ANNOUNCE_INTERVAL_SEC;
850
1065
t->announceMinIntervalSec = DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC;
851
1066
t->timesDownloaded = -1;
852
1067
t->seederCount = -1;
1068
t->downloaderCount = -1;
853
1069
t->leecherCount = -1;
854
1070
t->lastAnnounceResponse = -1;
855
1071
t->lastScrapeResponse = -1;
856
1072
t->manualAnnounceAllowedAt = ~(time_t)0;
857
t->name = tr_strdup( info->name );
858
t->randOffset = tr_rand( 30 );
1073
t->name = tr_strdup( info->name );
1074
t->torrentId = torrent->uniqueId;
1075
t->randOffset = tr_cryptoRandInt( 30 );
859
1076
memcpy( t->hash, info->hash, SHA_DIGEST_LENGTH );
860
1077
escape( t->escaped, info->hash, SHA_DIGEST_LENGTH );
861
1078
generateKeyParam( t->key_param, KEYLEN );
924
tr_trackerCanManualAnnounce ( const tr_tracker * t)
1141
tr_trackerCanManualAnnounce( const tr_tracker * t )
926
1143
const time_t allow = tr_trackerGetManualAnnounceTime( t );
927
1145
return allow && ( allow <= time( NULL ) );
931
tr_trackerGetCounts( const tr_tracker * t,
932
int * setme_completedCount,
933
int * setme_leecherCount,
934
int * setme_seederCount )
1149
tr_trackerGetCounts( const tr_tracker * t,
1150
int * setme_completedCount,
1151
int * setme_leecherCount,
1152
int * setme_seederCount,
1153
int * setme_downloaderCount )
936
1155
if( setme_completedCount )
937
*setme_completedCount = t->timesDownloaded;
1156
*setme_completedCount = t->timesDownloaded;
939
1158
if( setme_leecherCount )
940
*setme_leecherCount = t->leecherCount;
1159
*setme_leecherCount = t->leecherCount;
942
1161
if( setme_seederCount )
943
*setme_seederCount = t->seederCount;
1162
*setme_seederCount = t->seederCount;
1164
if( setme_downloaderCount )
1165
*setme_downloaderCount = t->downloaderCount;
948
1169
tr_trackerStart( tr_tracker * t )
950
1171
if( t && !t->isRunning )
1175
/* change the peer-id */
952
1176
tr_free( t->peer_id );
953
1177
t->peer_id = tr_peerIdNew( );
1178
if(( tor = tr_torrentFindFromHash( t->session, t->hash ))) {
1179
tr_free( tor->peer_id );
1180
tor->peer_id = (uint8_t*) tr_strdup( t->peer_id );
955
1183
t->isRunning = 1;
956
1184
enqueueRequest( t->session, t, TR_REQ_STARTED );
997
1227
setme->nextScrapeTime = t->scrapeAt;
998
1228
setme->lastAnnounceTime = t->lastAnnounceTime;
999
1229
setme->nextAnnounceTime = t->reannounceAt;
1000
setme->nextManualAnnounceTime = t->manualAnnounceAllowedAt;
1230
setme->manualAnnounceTime = t->manualAnnounceAllowedAt;
1002
1232
if( t->lastScrapeResponse == -1 ) /* never been scraped */
1003
1233
*setme->scrapeResponse = '\0';
1005
snprintf( setme->scrapeResponse,
1006
sizeof( setme->scrapeResponse ),
1008
tr_webGetResponseStr( t->lastScrapeResponse ),
1009
t->lastScrapeResponse );
1235
tr_snprintf( setme->scrapeResponse,
1236
sizeof( setme->scrapeResponse ),
1238
tr_webGetResponseStr( t->lastScrapeResponse ),
1239
t->lastScrapeResponse );
1011
1241
if( t->lastAnnounceResponse == -1 ) /* never been announced */
1012
1242
*setme->announceResponse = '\0';
1014
snprintf( setme->announceResponse,
1015
sizeof( setme->announceResponse ),
1017
tr_webGetResponseStr( t->lastAnnounceResponse ),
1018
t->lastAnnounceResponse );
1244
tr_snprintf( setme->announceResponse,
1245
sizeof( setme->announceResponse ),
1247
tr_webGetResponseStr( t->lastAnnounceResponse ),
1248
t->lastAnnounceResponse );