2007-08-16 20:00:06 +00:00
|
|
|
/*
|
2009-01-10 23:09:07 +00:00
|
|
|
* This file Copyright (C) 2007-2009 Charles Kerr <charles@transmissionbt.com>
|
2006-07-16 19:39:23 +00:00
|
|
|
*
|
2007-08-16 20:00:06 +00:00
|
|
|
* This file is licensed by the GPL version 2. Works owned by the
|
|
|
|
* Transmission project are granted a special exemption to clause 2(b)
|
2008-09-23 19:11:04 +00:00
|
|
|
* so that the bulk of its code can remain under the MIT license.
|
2007-08-16 20:00:06 +00:00
|
|
|
* This exemption does not extend to derived works not owned by
|
|
|
|
* the Transmission project.
|
2007-08-18 17:19:49 +00:00
|
|
|
*
|
|
|
|
* $Id$
|
2007-08-16 20:00:06 +00:00
|
|
|
*/
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-11-09 20:07:52 +00:00
|
|
|
#include <assert.h>
|
2007-07-29 18:11:21 +00:00
|
|
|
#include <stdlib.h>
|
2007-08-16 20:00:06 +00:00
|
|
|
#include <string.h> /* strcmp, strchr */
|
2007-07-29 18:11:21 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
#include <event.h>
|
2007-07-14 16:29:21 +00:00
|
|
|
|
2006-07-16 19:39:23 +00:00
|
|
|
#include "transmission.h"
|
2008-12-23 17:27:15 +00:00
|
|
|
#include "session.h"
|
2007-07-09 20:10:42 +00:00
|
|
|
#include "bencode.h"
|
2008-08-14 11:11:25 +00:00
|
|
|
#include "crypto.h"
|
2007-07-30 18:04:10 +00:00
|
|
|
#include "completion.h"
|
2007-07-09 20:10:42 +00:00
|
|
|
#include "net.h"
|
2007-08-16 20:00:06 +00:00
|
|
|
#include "publish.h"
|
2008-07-02 01:46:10 +00:00
|
|
|
#include "resume.h"
|
2007-12-25 05:37:32 +00:00
|
|
|
#include "torrent.h"
|
2007-07-30 18:04:10 +00:00
|
|
|
#include "tracker.h"
|
2007-08-18 03:02:32 +00:00
|
|
|
#include "trevent.h"
|
2007-07-30 18:04:10 +00:00
|
|
|
#include "utils.h"
|
2008-04-24 01:42:53 +00:00
|
|
|
#include "web.h"
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
enum
|
|
|
|
{
|
2008-10-15 16:43:51 +00:00
|
|
|
/* the announceAt fields are set to this when the action is disabled */
|
|
|
|
TR_TRACKER_STOPPED = 0,
|
|
|
|
|
|
|
|
/* the announceAt fields are set to this when the action is in progress */
|
|
|
|
TR_TRACKER_BUSY = 1,
|
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
HTTP_OK = 200,
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
/* seconds between tracker pulses */
|
2007-11-30 23:37:44 +00:00
|
|
|
PULSE_INTERVAL_MSEC = 1000,
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
/* unless the tracker says otherwise, rescrape this frequently */
|
2008-09-23 19:11:04 +00:00
|
|
|
DEFAULT_SCRAPE_INTERVAL_SEC = ( 60 * 15 ),
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
/* unless the tracker says otherwise, this is the announce interval */
|
2008-09-23 19:11:04 +00:00
|
|
|
DEFAULT_ANNOUNCE_INTERVAL_SEC = ( 60 * 4 ),
|
2007-10-17 01:17:30 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
/* unless the tracker says otherwise, this is the announce min_interval */
|
2008-09-23 19:11:04 +00:00
|
|
|
DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC = ( 60 * 2 ),
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-06-24 21:39:07 +00:00
|
|
|
/* how long to wait before a rescrape the first time we get an error */
|
|
|
|
FIRST_SCRAPE_RETRY_INTERVAL_SEC = 30,
|
|
|
|
|
|
|
|
/* how long to wait before a reannounce the first time we get an error */
|
|
|
|
FIRST_ANNOUNCE_RETRY_INTERVAL_SEC = 30,
|
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
/* the value of the 'numwant' argument passed in tracker requests. */
|
2009-01-03 07:23:26 +00:00
|
|
|
NUMWANT = 200,
|
2007-07-30 17:11:00 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
/* the length of the 'key' argument passed in tracker requests */
|
|
|
|
KEYLEN = 10
|
|
|
|
};
|
2006-12-17 16:36:27 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
/**
|
|
|
|
***
|
|
|
|
**/
|
2007-07-30 17:11:00 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
struct tr_tracker
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2008-11-28 22:11:41 +00:00
|
|
|
tr_bool isRunning;
|
2008-04-24 01:42:53 +00:00
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
uint8_t randOffset;
|
2008-04-24 01:42:53 +00:00
|
|
|
|
2008-05-26 13:13:24 +00:00
|
|
|
/* sent as the "key" argument in tracker requests
|
|
|
|
to verify us if our IP address changes.
|
|
|
|
This is immutable for the life of the tracker object. */
|
2008-09-23 19:11:04 +00:00
|
|
|
char key_param[KEYLEN + 1];
|
2007-08-18 03:02:32 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
/* these are set from the latest scrape or tracker response */
|
2008-09-23 19:11:04 +00:00
|
|
|
int announceIntervalSec;
|
|
|
|
int announceMinIntervalSec;
|
|
|
|
int scrapeIntervalSec;
|
|
|
|
int retryScrapeIntervalSec;
|
|
|
|
int retryAnnounceIntervalSec;
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
/* index into the torrent's tr_info.trackers array */
|
2008-09-23 19:11:04 +00:00
|
|
|
int trackerIndex;
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
tr_session * session;
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-12-29 18:10:07 +00:00
|
|
|
tr_publisher publisher;
|
2006-12-17 16:36:27 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
/* torrent hash string */
|
2008-09-23 19:11:04 +00:00
|
|
|
uint8_t hash[SHA_DIGEST_LENGTH];
|
|
|
|
char escaped[SHA_DIGEST_LENGTH * 3 + 1];
|
|
|
|
char * name;
|
2008-12-29 21:17:48 +00:00
|
|
|
int torrentId;
|
2007-04-08 05:41:44 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
/* corresponds to the peer_id sent as a tracker request parameter.
|
2007-10-23 14:00:17 +00:00
|
|
|
one tracker admin says: "When the same torrent is opened and
|
2007-08-16 20:00:06 +00:00
|
|
|
closed and opened again without quitting Transmission ...
|
|
|
|
change the peerid. It would help sometimes if a stopped event
|
|
|
|
was missed to ensure that we didn't think someone was cheating. */
|
2008-09-23 19:11:04 +00:00
|
|
|
uint8_t * peer_id;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
/* these are set from the latest tracker response... -1 is 'unknown' */
|
2008-09-23 19:11:04 +00:00
|
|
|
int timesDownloaded;
|
|
|
|
int seederCount;
|
2008-12-02 19:46:51 +00:00
|
|
|
int downloaderCount;
|
2008-09-23 19:11:04 +00:00
|
|
|
int leecherCount;
|
|
|
|
char * trackerID;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
time_t manualAnnounceAllowedAt;
|
|
|
|
time_t reannounceAt;
|
2008-08-21 20:18:34 +00:00
|
|
|
|
|
|
|
/* 0==never, 1==in progress, other values==when to scrape */
|
2008-09-23 19:11:04 +00:00
|
|
|
time_t scrapeAt;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
time_t lastScrapeTime;
|
|
|
|
long lastScrapeResponse;
|
2008-02-21 07:29:39 +00:00
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
time_t lastAnnounceTime;
|
|
|
|
long lastAnnounceResponse;
|
2007-10-17 18:59:58 +00:00
|
|
|
};
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-10-26 15:39:04 +00:00
|
|
|
#define dbgmsg( name, ... ) \
|
|
|
|
do { \
|
|
|
|
if( tr_deepLoggingIsActive( ) ) \
|
|
|
|
tr_deepLog( __FILE__, __LINE__, name, __VA_ARGS__ ); \
|
|
|
|
} while( 0 )
|
2007-10-18 03:55:55 +00:00
|
|
|
|
2007-08-18 08:28:57 +00:00
|
|
|
/***
|
2007-11-29 00:43:58 +00:00
|
|
|
****
|
2007-08-18 08:28:57 +00:00
|
|
|
***/
|
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
static const tr_tracker_info *
|
2008-09-23 19:11:04 +00:00
|
|
|
getCurrentAddressFromTorrent( tr_tracker * t,
|
|
|
|
const tr_torrent * tor )
|
2008-04-24 01:42:53 +00:00
|
|
|
{
|
2008-06-04 23:46:32 +00:00
|
|
|
/* user might have removed trackers,
|
|
|
|
* so check to make sure our current index is in-bounds */
|
|
|
|
if( t->trackerIndex >= tor->info.trackerCount )
|
|
|
|
t->trackerIndex = 0;
|
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
assert( t->trackerIndex >= 0 );
|
|
|
|
assert( t->trackerIndex < tor->info.trackerCount );
|
|
|
|
return tor->info.trackers + t->trackerIndex;
|
|
|
|
}
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2008-03-18 16:56:01 +00:00
|
|
|
static const tr_tracker_info *
|
2008-06-04 23:46:32 +00:00
|
|
|
getCurrentAddress( tr_tracker * t )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
const tr_torrent * torrent;
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2009-01-03 23:11:29 +00:00
|
|
|
if( ( torrent = tr_torrentFindFromId( t->session, t->torrentId ) ) )
|
2008-04-24 01:42:53 +00:00
|
|
|
return getCurrentAddressFromTorrent( t, torrent );
|
|
|
|
return NULL;
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
|
|
|
|
2007-10-07 16:07:19 +00:00
|
|
|
static int
|
2008-09-23 19:11:04 +00:00
|
|
|
trackerSupportsScrape( tr_tracker * t,
|
|
|
|
const tr_torrent * tor )
|
2007-08-18 08:28:57 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
const tr_tracker_info * info = getCurrentAddressFromTorrent( t, tor );
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
return info && info->scrape;
|
2007-10-07 16:07:19 +00:00
|
|
|
}
|
2007-08-18 08:28:57 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
|
|
|
|
2008-08-11 19:05:02 +00:00
|
|
|
static tr_tracker *
|
2008-12-29 21:17:48 +00:00
|
|
|
findTracker( tr_session * session, int torrentId )
|
2007-10-07 16:07:19 +00:00
|
|
|
{
|
2008-12-29 21:17:48 +00:00
|
|
|
tr_torrent * torrent = tr_torrentFindFromId( session, torrentId );
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2007-11-30 17:10:33 +00:00
|
|
|
return torrent ? torrent->tracker : NULL;
|
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
/***
|
|
|
|
**** PUBLISH
|
|
|
|
***/
|
2007-02-27 04:00:38 +00:00
|
|
|
|
2008-12-29 21:17:48 +00:00
|
|
|
static const tr_tracker_event emptyEvent = { 0, NULL, NULL, 0, 0 };
|
2007-08-16 20:00:06 +00:00
|
|
|
|
|
|
|
static void
|
2008-09-23 19:11:04 +00:00
|
|
|
publishMessage( tr_tracker * t,
|
|
|
|
const char * msg,
|
|
|
|
int type )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
if( t )
|
2007-11-30 23:37:44 +00:00
|
|
|
{
|
|
|
|
tr_tracker_event event = emptyEvent;
|
|
|
|
event.messageType = type;
|
|
|
|
event.text = msg;
|
2008-12-29 18:10:07 +00:00
|
|
|
tr_publisherPublish( &t->publisher, t, &event );
|
2007-11-30 23:37:44 +00:00
|
|
|
}
|
2007-08-16 20:00:06 +00:00
|
|
|
}
|
2007-09-25 18:39:58 +00:00
|
|
|
|
|
|
|
static void
|
2007-10-17 18:59:58 +00:00
|
|
|
publishErrorClear( tr_tracker * t )
|
2007-09-25 18:39:58 +00:00
|
|
|
{
|
2007-10-17 18:59:58 +00:00
|
|
|
publishMessage( t, NULL, TR_TRACKER_ERROR_CLEAR );
|
2007-09-25 18:39:58 +00:00
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
static void
|
2008-09-23 19:11:04 +00:00
|
|
|
publishErrorMessageAndStop( tr_tracker * t,
|
|
|
|
const char * msg )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2007-11-30 23:37:44 +00:00
|
|
|
t->isRunning = 0;
|
2007-10-17 18:59:58 +00:00
|
|
|
publishMessage( t, msg, TR_TRACKER_ERROR );
|
2007-08-16 20:00:06 +00:00
|
|
|
}
|
2007-09-25 18:39:58 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
static void
|
2008-09-23 19:11:04 +00:00
|
|
|
publishWarning( tr_tracker * t,
|
|
|
|
const char * msg )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2007-10-17 18:59:58 +00:00
|
|
|
publishMessage( t, msg, TR_TRACKER_WARNING );
|
2006-12-17 16:36:27 +00:00
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
static void
|
2008-09-23 19:11:04 +00:00
|
|
|
publishNewPeers( tr_tracker * t,
|
|
|
|
int allAreSeeds,
|
|
|
|
void * compact,
|
|
|
|
int compactLen )
|
2006-12-17 16:36:27 +00:00
|
|
|
{
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_tracker_event event = emptyEvent;
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
event.messageType = TR_TRACKER_PEERS;
|
2008-04-19 15:07:59 +00:00
|
|
|
event.allAreSeeds = allAreSeeds;
|
|
|
|
event.compact = compact;
|
|
|
|
event.compactLen = compactLen;
|
|
|
|
if( compactLen )
|
2008-12-29 18:10:07 +00:00
|
|
|
tr_publisherPublish( &t->publisher, t, &event );
|
2007-07-30 17:11:00 +00:00
|
|
|
}
|
|
|
|
|
2008-12-15 00:17:08 +00:00
|
|
|
static void
|
|
|
|
publishNewPeersCompact( tr_tracker * t,
|
|
|
|
int allAreSeeds,
|
|
|
|
void * compact,
|
|
|
|
int compactLen )
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
uint8_t *array, *walk, *compactWalk;
|
|
|
|
const int peerCount = compactLen / 6;
|
|
|
|
const int arrayLen = peerCount * ( sizeof( tr_address ) + 2 );
|
|
|
|
tr_address addr;
|
|
|
|
tr_port port;
|
|
|
|
|
|
|
|
addr.type = TR_AF_INET;
|
|
|
|
memset( &addr.addr, 0x00, sizeof( addr.addr ) );
|
|
|
|
array = tr_new( uint8_t, arrayLen );
|
|
|
|
for ( i = 0, walk = array, compactWalk = compact ; i < peerCount ; i++ )
|
|
|
|
{
|
|
|
|
memcpy( &addr.addr.addr4, compactWalk, 4 );
|
|
|
|
memcpy( &port, compactWalk + 4, 2 );
|
|
|
|
|
|
|
|
memcpy( walk, &addr, sizeof( addr ) );
|
|
|
|
memcpy( walk + sizeof( addr ), &port, 2 );
|
|
|
|
|
|
|
|
walk += sizeof( tr_address ) + 2;
|
|
|
|
compactWalk += 6;
|
|
|
|
}
|
|
|
|
publishNewPeers( t, allAreSeeds, array, arrayLen );
|
|
|
|
tr_free( array );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
publishNewPeersCompact6( tr_tracker * t,
|
|
|
|
int allAreSeeds,
|
|
|
|
void * compact,
|
|
|
|
int compactLen )
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
uint8_t *array, *walk, *compactWalk;
|
|
|
|
const int peerCount = compactLen / 18;
|
|
|
|
const int arrayLen = peerCount * ( sizeof( tr_address ) + 2 );
|
|
|
|
tr_address addr;
|
|
|
|
tr_port port;
|
|
|
|
|
|
|
|
addr.type = TR_AF_INET6;
|
|
|
|
memset( &addr.addr, 0x00, sizeof( addr.addr ) );
|
|
|
|
array = tr_new( uint8_t, arrayLen );
|
|
|
|
for ( i = 0, walk = array, compactWalk = compact ; i < peerCount ; i++ )
|
|
|
|
{
|
|
|
|
memcpy( &addr.addr.addr6, compactWalk, 16 );
|
|
|
|
memcpy( &port, compactWalk + 16, 2 );
|
2009-01-16 06:40:23 +00:00
|
|
|
compactWalk += 18;
|
2008-12-15 00:17:08 +00:00
|
|
|
|
|
|
|
memcpy( walk, &addr, sizeof( addr ) );
|
|
|
|
memcpy( walk + sizeof( addr ), &port, 2 );
|
|
|
|
walk += sizeof( tr_address ) + 2;
|
|
|
|
}
|
|
|
|
publishNewPeers( t, allAreSeeds, array, arrayLen );
|
|
|
|
tr_free( array );
|
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
/***
|
2007-11-29 00:43:58 +00:00
|
|
|
****
|
2007-08-16 20:00:06 +00:00
|
|
|
***/
|
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
static void onReqDone( tr_session * session );
|
2007-07-30 17:11:00 +00:00
|
|
|
|
2008-05-05 20:11:03 +00:00
|
|
|
static int
|
2008-09-23 19:11:04 +00:00
|
|
|
updateAddresses( tr_tracker * t,
|
|
|
|
int success )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
int retry;
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-05-05 20:11:03 +00:00
|
|
|
tr_torrent * torrent = tr_torrentFindFromHash( t->session, t->hash );
|
2008-04-29 01:21:42 +00:00
|
|
|
|
2008-05-05 20:11:03 +00:00
|
|
|
if( success )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
/* multitracker spec: "if a connection with a tracker is
|
|
|
|
successful, it will be moved to the front of the tier." */
|
2008-11-12 04:27:02 +00:00
|
|
|
t->trackerIndex = tr_torrentPromoteTracker( torrent, t->trackerIndex );
|
2008-05-05 20:11:03 +00:00
|
|
|
retry = FALSE; /* we succeeded; no need to retry */
|
2006-12-02 01:46:54 +00:00
|
|
|
}
|
2008-09-23 19:11:04 +00:00
|
|
|
else if( ++t->trackerIndex >= torrent->info.trackerCount )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2008-05-05 20:11:03 +00:00
|
|
|
t->trackerIndex = 0;
|
|
|
|
retry = FALSE; /* we've tried them all */
|
2007-08-16 20:00:06 +00:00
|
|
|
}
|
2008-05-05 20:11:03 +00:00
|
|
|
else
|
2008-02-13 17:15:58 +00:00
|
|
|
{
|
2008-11-12 04:27:02 +00:00
|
|
|
const tr_tracker_info * n = getCurrentAddressFromTorrent( t, torrent );
|
2008-05-05 20:11:03 +00:00
|
|
|
tr_ninf( t->name, _( "Trying tracker \"%s\"" ), n->announce );
|
|
|
|
retry = TRUE;
|
2008-02-13 17:15:58 +00:00
|
|
|
}
|
2008-05-05 20:11:03 +00:00
|
|
|
|
|
|
|
return retry;
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static uint8_t *
|
2008-09-23 19:11:04 +00:00
|
|
|
parseOldPeers( tr_benc * bePeers,
|
|
|
|
size_t * byteCount )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
int i;
|
2008-12-15 00:17:08 +00:00
|
|
|
uint8_t * array, *walk;
|
2007-11-29 00:43:58 +00:00
|
|
|
const int peerCount = bePeers->val.l.count;
|
2007-08-20 23:37:08 +00:00
|
|
|
|
2009-04-05 18:02:11 +00:00
|
|
|
assert( tr_bencIsList( bePeers ) );
|
2007-08-20 23:37:08 +00:00
|
|
|
|
2008-12-15 00:17:08 +00:00
|
|
|
array = tr_new( uint8_t, peerCount * ( sizeof( tr_address ) + 2 ) );
|
2007-08-20 23:37:08 +00:00
|
|
|
|
2008-12-15 00:17:08 +00:00
|
|
|
for( i = 0, walk = array; i < peerCount; ++i )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-12-15 00:17:08 +00:00
|
|
|
const char * s;
|
|
|
|
int64_t itmp;
|
|
|
|
tr_address addr;
|
2008-12-21 19:13:52 +00:00
|
|
|
tr_port port;
|
|
|
|
tr_benc * peer = &bePeers->val.l.vals[i];
|
2007-10-11 14:56:50 +00:00
|
|
|
|
2008-12-15 00:17:08 +00:00
|
|
|
if( tr_bencDictFindStr( peer, "ip", &s ) )
|
|
|
|
{
|
|
|
|
if( tr_pton( s, &addr ) == NULL )
|
|
|
|
continue;
|
|
|
|
}
|
2008-09-23 19:11:04 +00:00
|
|
|
if( !tr_bencDictFindInt( peer, "port",
|
|
|
|
&itmp ) || itmp < 0 || itmp > 0xffff )
|
2007-11-29 00:43:58 +00:00
|
|
|
continue;
|
2007-10-11 14:56:50 +00:00
|
|
|
|
2008-12-15 00:17:08 +00:00
|
|
|
memcpy( walk, &addr, sizeof( tr_address ) );
|
2008-04-24 01:42:53 +00:00
|
|
|
port = htons( itmp );
|
2008-12-15 00:17:08 +00:00
|
|
|
memcpy( walk + sizeof( tr_address ), &port, 2 );
|
|
|
|
walk += sizeof( tr_address ) + 2;
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
2007-10-11 14:56:50 +00:00
|
|
|
|
2008-12-15 00:17:08 +00:00
|
|
|
*byteCount = peerCount * sizeof( tr_address ) + 2;
|
|
|
|
return array;
|
2007-10-11 14:56:50 +00:00
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
static void
|
2008-12-29 21:17:48 +00:00
|
|
|
onStoppedResponse( tr_session * session,
|
2008-09-23 19:11:04 +00:00
|
|
|
long responseCode UNUSED,
|
|
|
|
const void * response UNUSED,
|
|
|
|
size_t responseLen UNUSED,
|
2008-12-29 21:17:48 +00:00
|
|
|
void * torrentId )
|
2008-04-24 01:42:53 +00:00
|
|
|
{
|
2008-12-29 21:17:48 +00:00
|
|
|
tr_tracker * t = findTracker( session, tr_ptr2int( torrentId ) );
|
2008-10-15 16:43:51 +00:00
|
|
|
if( t )
|
|
|
|
{
|
|
|
|
const time_t now = time( NULL );
|
|
|
|
|
|
|
|
t->reannounceAt = TR_TRACKER_STOPPED;
|
|
|
|
t->manualAnnounceAllowedAt = TR_TRACKER_STOPPED;
|
|
|
|
|
|
|
|
if( t->scrapeAt <= now )
|
|
|
|
t->scrapeAt = now + t->scrapeIntervalSec + t->randOffset;
|
|
|
|
}
|
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
dbgmsg( NULL, "got a response to some `stop' message" );
|
|
|
|
onReqDone( session );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-09-23 19:11:04 +00:00
|
|
|
onTrackerResponse( tr_session * session,
|
|
|
|
long responseCode,
|
|
|
|
const void * response,
|
|
|
|
size_t responseLen,
|
2008-12-29 21:17:48 +00:00
|
|
|
void * torrentId )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2008-10-15 17:53:42 +00:00
|
|
|
int retry;
|
|
|
|
int success = FALSE;
|
|
|
|
int scrapeFields = 0;
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_tracker * t;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
onReqDone( session );
|
2008-12-29 21:17:48 +00:00
|
|
|
t = findTracker( session, tr_ptr2int( torrentId ) );
|
2008-04-24 01:42:53 +00:00
|
|
|
if( !t ) /* tracker's been closed */
|
2007-11-29 00:43:58 +00:00
|
|
|
return;
|
|
|
|
|
2008-05-18 16:44:30 +00:00
|
|
|
dbgmsg( t->name, "tracker response: %ld", responseCode );
|
|
|
|
tr_ndbg( t->name, "tracker response: %ld", responseCode );
|
2008-04-24 01:42:53 +00:00
|
|
|
t->lastAnnounceResponse = responseCode;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if( responseCode == HTTP_OK )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
tr_benc benc;
|
2008-08-11 19:05:02 +00:00
|
|
|
const int bencLoaded = !tr_bencLoad( response, responseLen,
|
|
|
|
&benc, NULL );
|
2007-11-29 00:43:58 +00:00
|
|
|
publishErrorClear( t );
|
2008-04-24 01:42:53 +00:00
|
|
|
if( bencLoaded && tr_bencIsDict( &benc ) )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
tr_benc * tmp;
|
|
|
|
int64_t i;
|
|
|
|
int incomplete = -1;
|
2008-04-24 01:42:53 +00:00
|
|
|
const char * str;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-05-05 20:11:03 +00:00
|
|
|
success = TRUE;
|
2008-06-24 21:39:07 +00:00
|
|
|
t->retryAnnounceIntervalSec = FIRST_SCRAPE_RETRY_INTERVAL_SEC;
|
2008-05-05 20:11:03 +00:00
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
if( ( tr_bencDictFindStr( &benc, "failure reason", &str ) ) )
|
|
|
|
{
|
2008-04-29 01:21:42 +00:00
|
|
|
publishMessage( t, str, TR_TRACKER_ERROR );
|
2008-05-05 20:11:03 +00:00
|
|
|
success = FALSE;
|
2008-04-29 01:21:42 +00:00
|
|
|
}
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
if( ( tr_bencDictFindStr( &benc, "warning message", &str ) ) )
|
2008-04-24 01:42:53 +00:00
|
|
|
publishWarning( t, str );
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
if( ( tr_bencDictFindInt( &benc, "interval", &i ) ) )
|
|
|
|
{
|
2008-04-25 02:57:33 +00:00
|
|
|
dbgmsg( t->name, "setting interval to %d", (int)i );
|
2008-04-24 01:42:53 +00:00
|
|
|
t->announceIntervalSec = i;
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
if( ( tr_bencDictFindInt( &benc, "min interval", &i ) ) )
|
|
|
|
{
|
2008-04-25 02:57:33 +00:00
|
|
|
dbgmsg( t->name, "setting min interval to %d", (int)i );
|
2008-04-24 01:42:53 +00:00
|
|
|
t->announceMinIntervalSec = i;
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
if( ( tr_bencDictFindStr( &benc, "tracker id", &str ) ) )
|
2008-04-24 01:42:53 +00:00
|
|
|
t->trackerID = tr_strdup( str );
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
if( ( tr_bencDictFindInt( &benc, "complete", &i ) ) )
|
2008-10-15 17:53:42 +00:00
|
|
|
{
|
|
|
|
++scrapeFields;
|
2008-04-24 01:42:53 +00:00
|
|
|
t->seederCount = i;
|
2008-10-15 17:53:42 +00:00
|
|
|
}
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
if( ( tr_bencDictFindInt( &benc, "incomplete", &i ) ) )
|
2008-10-15 17:53:42 +00:00
|
|
|
{
|
|
|
|
++scrapeFields;
|
2008-04-24 01:42:53 +00:00
|
|
|
t->leecherCount = incomplete = i;
|
2008-10-15 17:53:42 +00:00
|
|
|
}
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
if( ( tr_bencDictFindInt( &benc, "downloaded", &i ) ) )
|
2008-10-15 17:53:42 +00:00
|
|
|
{
|
|
|
|
++scrapeFields;
|
2008-09-14 00:57:11 +00:00
|
|
|
t->timesDownloaded = i;
|
2008-10-15 17:53:42 +00:00
|
|
|
}
|
2008-09-14 00:57:11 +00:00
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
if( ( tmp = tr_bencDictFind( &benc, "peers" ) ) )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-04-19 15:07:59 +00:00
|
|
|
const int allAreSeeds = incomplete == 0;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2009-04-05 18:02:11 +00:00
|
|
|
if( tr_bencIsString( tmp ) ) /* "compact" extension */
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-12-15 00:17:08 +00:00
|
|
|
publishNewPeersCompact( t, allAreSeeds, tmp->val.s.s,
|
|
|
|
tmp->val.s.i );
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
2009-04-05 18:02:11 +00:00
|
|
|
else if( tr_bencIsList( tmp ) ) /* original protocol */
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
size_t byteCount = 0;
|
2008-12-15 00:17:08 +00:00
|
|
|
uint8_t * array = parseOldPeers( tmp, &byteCount );
|
|
|
|
publishNewPeers( t, allAreSeeds, array, byteCount );
|
|
|
|
tr_free( array );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ( tmp = tr_bencDictFind( &benc, "peers6" ) ) )
|
|
|
|
{
|
|
|
|
const int allAreSeeds = incomplete == 0;
|
|
|
|
|
2009-04-21 16:52:28 +00:00
|
|
|
if( tr_bencIsString( tmp ) ) /* "compact" extension */
|
2008-12-15 00:17:08 +00:00
|
|
|
{
|
|
|
|
publishNewPeersCompact6( t, allAreSeeds, tmp->val.s.s,
|
|
|
|
tmp->val.s.i );
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( bencLoaded )
|
|
|
|
tr_bencFree( &benc );
|
|
|
|
}
|
2008-11-12 04:27:02 +00:00
|
|
|
else if( responseCode )
|
2008-10-27 18:00:03 +00:00
|
|
|
{
|
2008-10-27 18:09:15 +00:00
|
|
|
/* %1$ld - http status code, such as 404
|
|
|
|
* %2$s - human-readable explanation of the http status code */
|
|
|
|
char * buf = tr_strdup_printf( _( "Tracker request failed. Got HTTP Status Code %1$ld (%2$s)" ),
|
2008-10-27 18:00:03 +00:00
|
|
|
responseCode,
|
|
|
|
tr_webGetResponseStr( responseCode ) );
|
|
|
|
publishWarning( t, buf );
|
|
|
|
tr_free( buf );
|
|
|
|
}
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-05-05 20:11:03 +00:00
|
|
|
retry = updateAddresses( t, success );
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-11-12 04:27:02 +00:00
|
|
|
if( responseCode && retry )
|
2008-02-13 17:15:58 +00:00
|
|
|
responseCode = 300;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-11-12 04:27:02 +00:00
|
|
|
if( responseCode == 0 )
|
|
|
|
{
|
|
|
|
dbgmsg( t->name, "No response from tracker... retrying in two minutes." );
|
|
|
|
t->manualAnnounceAllowedAt = ~(time_t)0;
|
|
|
|
t->reannounceAt = time( NULL ) + t->randOffset + 120;
|
|
|
|
}
|
|
|
|
else if( 200 <= responseCode && responseCode <= 299 )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
const int interval = t->announceIntervalSec + t->randOffset;
|
2008-04-25 16:06:03 +00:00
|
|
|
const time_t now = time ( NULL );
|
2008-11-12 04:27:02 +00:00
|
|
|
dbgmsg( t->name, "request succeeded. reannouncing in %d seconds", interval );
|
2008-10-15 17:53:42 +00:00
|
|
|
|
|
|
|
/* if the announce response was a superset of the scrape response,
|
|
|
|
treat this as both a successful announce AND scrape. */
|
|
|
|
if( scrapeFields >= 3 ) {
|
|
|
|
t->lastScrapeResponse = responseCode;
|
|
|
|
t->lastScrapeTime = now;
|
2008-09-18 16:18:50 +00:00
|
|
|
t->scrapeAt = now + t->scrapeIntervalSec + t->randOffset;
|
2008-10-15 17:53:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* most trackers don't provide all the scrape responses, but do
|
|
|
|
provide most of them, so don't scrape too soon anyway */
|
|
|
|
if( ( scrapeFields == 2 ) && ( t->scrapeAt <= ( now + 120 ) ) ) {
|
|
|
|
t->scrapeAt = now + t->scrapeIntervalSec + t->randOffset;
|
|
|
|
}
|
|
|
|
|
2008-04-25 16:06:03 +00:00
|
|
|
t->reannounceAt = now + interval;
|
|
|
|
t->manualAnnounceAllowedAt = now + t->announceMinIntervalSec;
|
2008-07-02 01:46:10 +00:00
|
|
|
|
|
|
|
/* #319: save the .resume file after an announce so that, in case
|
|
|
|
* of a crash, our stats still match up with the tracker's stats */
|
|
|
|
tr_torrentSaveResume( tr_torrentFindFromHash( t->session, t->hash ) );
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
2008-09-23 19:11:04 +00:00
|
|
|
else if( 300 <= responseCode && responseCode <= 399 )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
|
|
|
/* it's a redirect... updateAddresses() has already
|
|
|
|
* parsed the redirect, all that's left is to retry */
|
2008-04-24 01:42:53 +00:00
|
|
|
const int interval = 5;
|
2008-04-25 02:57:33 +00:00
|
|
|
dbgmsg( t->name, "got a redirect. retrying in %d seconds", interval );
|
2008-03-18 19:33:08 +00:00
|
|
|
t->reannounceAt = time( NULL ) + interval;
|
2008-11-12 04:27:02 +00:00
|
|
|
t->manualAnnounceAllowedAt = time( NULL ) + t->announceMinIntervalSec;
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
2008-09-23 19:11:04 +00:00
|
|
|
else if( 400 <= responseCode && responseCode <= 499 )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
|
|
|
/* The request could not be understood by the server due to
|
|
|
|
* malformed syntax. The client SHOULD NOT repeat the
|
|
|
|
* request without modifications. */
|
2008-04-24 01:42:53 +00:00
|
|
|
publishErrorMessageAndStop( t, _( "Tracker returned a 4xx message" ) );
|
2007-11-29 00:43:58 +00:00
|
|
|
t->manualAnnounceAllowedAt = ~(time_t)0;
|
2008-10-15 16:43:51 +00:00
|
|
|
t->reannounceAt = TR_TRACKER_STOPPED;
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
2008-09-23 19:11:04 +00:00
|
|
|
else if( 500 <= responseCode && responseCode <= 599 )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
|
|
|
/* Response status codes beginning with the digit "5" indicate
|
|
|
|
* cases in which the server is aware that it has erred or is
|
|
|
|
* incapable of performing the request. So we pause a bit and
|
|
|
|
* try again. */
|
|
|
|
t->manualAnnounceAllowedAt = ~(time_t)0;
|
2008-06-24 21:39:07 +00:00
|
|
|
t->reannounceAt = time( NULL ) + t->retryAnnounceIntervalSec;
|
|
|
|
t->retryAnnounceIntervalSec *= 2;
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* WTF did we get?? */
|
2008-11-12 04:27:02 +00:00
|
|
|
dbgmsg( t->name, "Invalid response from tracker... retrying in two minutes." );
|
2007-11-29 00:43:58 +00:00
|
|
|
t->manualAnnounceAllowedAt = ~(time_t)0;
|
2008-01-19 01:34:02 +00:00
|
|
|
t->reannounceAt = time( NULL ) + t->randOffset + 120;
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-09-23 19:11:04 +00:00
|
|
|
onScrapeResponse( tr_session * session,
|
|
|
|
long responseCode,
|
|
|
|
const void * response,
|
|
|
|
size_t responseLen,
|
2008-12-29 21:17:48 +00:00
|
|
|
void * torrentId )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
int success = FALSE;
|
|
|
|
int retry;
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_tracker * t;
|
2007-12-05 02:06:05 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
onReqDone( session );
|
2008-12-29 21:17:48 +00:00
|
|
|
t = findTracker( session, tr_ptr2int( torrentId ) );
|
2008-04-24 01:42:53 +00:00
|
|
|
if( !t ) /* tracker's been closed... */
|
2007-10-08 19:09:20 +00:00
|
|
|
return;
|
|
|
|
|
2008-04-25 02:57:33 +00:00
|
|
|
dbgmsg( t->name, "scrape response: %ld\n", responseCode );
|
2008-05-18 16:44:30 +00:00
|
|
|
tr_ndbg( t->name, "scrape response: %ld", responseCode );
|
2008-04-24 01:42:53 +00:00
|
|
|
t->lastScrapeResponse = responseCode;
|
2007-10-17 18:59:58 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if( responseCode == HTTP_OK )
|
2007-01-20 05:07:00 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
tr_benc benc, *files;
|
2008-08-11 19:05:02 +00:00
|
|
|
const int bencLoaded = !tr_bencLoad( response, responseLen,
|
|
|
|
&benc, NULL );
|
2008-04-24 01:42:53 +00:00
|
|
|
if( bencLoaded && tr_bencDictFindDict( &benc, "files", &files ) )
|
2007-01-20 05:07:00 +00:00
|
|
|
{
|
2008-09-04 14:42:32 +00:00
|
|
|
size_t i;
|
2008-09-23 19:11:04 +00:00
|
|
|
for( i = 0; i < files->val.l.count; i += 2 )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
int64_t itmp;
|
2007-08-16 20:00:06 +00:00
|
|
|
const uint8_t* hash =
|
2008-04-24 01:42:53 +00:00
|
|
|
(const uint8_t*) files->val.l.vals[i].val.s.s;
|
2008-09-23 19:11:04 +00:00
|
|
|
tr_benc * flags;
|
|
|
|
tr_benc * tordict = &files->val.l.vals[i + 1];
|
2007-10-17 18:59:58 +00:00
|
|
|
if( memcmp( t->hash, hash, SHA_DIGEST_LENGTH ) )
|
2007-08-16 20:00:06 +00:00
|
|
|
continue;
|
2007-01-20 05:07:00 +00:00
|
|
|
|
2007-10-17 18:59:58 +00:00
|
|
|
publishErrorClear( t );
|
2007-09-25 18:39:58 +00:00
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
if( ( tr_bencDictFindInt( tordict, "complete", &itmp ) ) )
|
2008-04-24 01:42:53 +00:00
|
|
|
t->seederCount = itmp;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
if( ( tr_bencDictFindInt( tordict, "incomplete", &itmp ) ) )
|
2008-04-24 01:42:53 +00:00
|
|
|
t->leecherCount = itmp;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
if( ( tr_bencDictFindInt( tordict, "downloaded", &itmp ) ) )
|
2008-04-24 01:42:53 +00:00
|
|
|
t->timesDownloaded = itmp;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2008-12-02 19:46:51 +00:00
|
|
|
if( ( tr_bencDictFindInt( tordict, "downloaders", &itmp ) ) )
|
|
|
|
t->downloaderCount = itmp;
|
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
if( tr_bencDictFindDict( tordict, "flags", &flags ) )
|
2008-12-02 19:46:51 +00:00
|
|
|
if( ( tr_bencDictFindInt( flags, "min_request_interval", &itmp ) ) )
|
2008-04-24 01:42:53 +00:00
|
|
|
t->scrapeIntervalSec = i;
|
2006-12-02 01:46:54 +00:00
|
|
|
|
2008-07-02 01:17:57 +00:00
|
|
|
/* as per ticket #1045, safeguard against trackers returning
|
|
|
|
* a very low min_request_interval... */
|
|
|
|
if( t->scrapeIntervalSec < DEFAULT_SCRAPE_INTERVAL_SEC )
|
|
|
|
t->scrapeIntervalSec = DEFAULT_SCRAPE_INTERVAL_SEC;
|
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
tr_ndbg( t->name,
|
2009-02-06 21:17:23 +00:00
|
|
|
"Scrape successful. Rescraping in %d seconds.",
|
2008-03-13 03:53:18 +00:00
|
|
|
t->scrapeIntervalSec );
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-06-24 21:39:07 +00:00
|
|
|
success = TRUE;
|
|
|
|
t->retryScrapeIntervalSec = FIRST_SCRAPE_RETRY_INTERVAL_SEC;
|
2007-08-16 20:00:06 +00:00
|
|
|
}
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
if( bencLoaded )
|
|
|
|
tr_bencFree( &benc );
|
2006-10-13 07:42:55 +00:00
|
|
|
}
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-05-05 20:11:03 +00:00
|
|
|
retry = updateAddresses( t, success );
|
2006-10-13 07:42:55 +00:00
|
|
|
|
2008-04-12 22:37:03 +00:00
|
|
|
/**
|
|
|
|
***
|
|
|
|
**/
|
|
|
|
|
2008-05-05 20:11:03 +00:00
|
|
|
if( retry )
|
2008-04-12 22:37:03 +00:00
|
|
|
responseCode = 300;
|
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
if( 200 <= responseCode && responseCode <= 299 )
|
2008-04-12 22:37:03 +00:00
|
|
|
{
|
|
|
|
const int interval = t->scrapeIntervalSec + t->randOffset;
|
2009-02-06 21:17:23 +00:00
|
|
|
dbgmsg( t->name, "Request succeeded. Rescraping in %d seconds",
|
2008-09-23 19:11:04 +00:00
|
|
|
interval );
|
2009-02-06 21:17:23 +00:00
|
|
|
tr_ndbg( t->name, "Request succeeded. Rescraping in %d seconds",
|
2008-09-23 19:11:04 +00:00
|
|
|
interval );
|
2008-04-12 22:37:03 +00:00
|
|
|
t->scrapeAt = time( NULL ) + interval;
|
|
|
|
}
|
2008-09-23 19:11:04 +00:00
|
|
|
else if( 300 <= responseCode && responseCode <= 399 )
|
2008-04-12 22:37:03 +00:00
|
|
|
{
|
|
|
|
const int interval = 5;
|
2009-02-06 21:17:23 +00:00
|
|
|
dbgmsg( t->name, "Got a redirect. Retrying in %d seconds", interval );
|
2008-04-12 22:37:03 +00:00
|
|
|
t->scrapeAt = time( NULL ) + interval;
|
|
|
|
}
|
2008-02-13 17:15:58 +00:00
|
|
|
else
|
2008-04-12 22:37:03 +00:00
|
|
|
{
|
|
|
|
const int interval = t->retryScrapeIntervalSec + t->randOffset;
|
2008-09-23 19:11:04 +00:00
|
|
|
dbgmsg(
|
|
|
|
t->name,
|
2009-02-06 21:17:23 +00:00
|
|
|
"Tracker responded to scrape with %ld. Retrying in %d seconds.",
|
2008-09-23 19:11:04 +00:00
|
|
|
responseCode, interval );
|
2008-04-12 22:37:03 +00:00
|
|
|
t->retryScrapeIntervalSec *= 2;
|
|
|
|
t->scrapeAt = time( NULL ) + interval;
|
|
|
|
}
|
2006-12-02 01:46:54 +00:00
|
|
|
}
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
2007-10-17 18:59:58 +00:00
|
|
|
|
2007-11-30 17:10:33 +00:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
TR_REQ_STARTED,
|
|
|
|
TR_REQ_COMPLETED,
|
|
|
|
TR_REQ_STOPPED,
|
2008-12-02 19:46:51 +00:00
|
|
|
TR_REQ_PAUSED, /* BEP 21 */
|
2007-11-30 17:10:33 +00:00
|
|
|
TR_REQ_REANNOUNCE,
|
2009-02-04 17:38:40 +00:00
|
|
|
TR_REQ_SCRAPE,
|
|
|
|
TR_NUM_REQ_TYPES
|
2007-11-30 17:10:33 +00:00
|
|
|
};
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
struct tr_tracker_request
|
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
int reqtype; /* TR_REQ_* */
|
2008-12-29 21:17:48 +00:00
|
|
|
int torrentId;
|
2008-12-30 00:56:10 +00:00
|
|
|
struct evbuffer * url;
|
|
|
|
tr_web_done_func * done_func;
|
2008-09-23 19:11:04 +00:00
|
|
|
tr_session * session;
|
2007-11-29 00:43:58 +00:00
|
|
|
};
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static void
|
2007-11-29 02:31:21 +00:00
|
|
|
freeRequest( struct tr_tracker_request * req )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-12-30 00:56:10 +00:00
|
|
|
evbuffer_free( req->url );
|
2007-11-29 02:31:21 +00:00
|
|
|
tr_free( req );
|
2007-08-16 20:00:06 +00:00
|
|
|
}
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static void
|
2008-09-23 19:11:04 +00:00
|
|
|
buildTrackerRequestURI( tr_tracker * t,
|
|
|
|
const tr_torrent * torrent,
|
|
|
|
const char * eventName,
|
|
|
|
struct evbuffer * buf )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
const int isStopping = !strcmp( eventName, "stopped" );
|
|
|
|
const int numwant = isStopping ? 0 : NUMWANT;
|
|
|
|
const char * ann = getCurrentAddressFromTorrent( t, torrent )->announce;
|
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
evbuffer_add_printf( buf, "%cinfo_hash=%s"
|
2007-10-17 18:59:58 +00:00
|
|
|
"&peer_id=%s"
|
|
|
|
"&port=%d"
|
2008-09-23 19:11:04 +00:00
|
|
|
"&uploaded=%" PRIu64
|
2008-12-02 18:24:26 +00:00
|
|
|
"&downloaded=%" PRIu64
|
|
|
|
"&corrupt=%" PRIu64
|
|
|
|
"&left=%" PRIu64
|
|
|
|
"&compact=1"
|
|
|
|
"&numwant=%d"
|
|
|
|
"&key=%s",
|
|
|
|
strchr( ann, '?' ) ? '&' : '?',
|
|
|
|
t->escaped,
|
|
|
|
t->peer_id,
|
|
|
|
tr_sessionGetPeerPort( t->session ),
|
|
|
|
torrent->uploadedCur,
|
|
|
|
torrent->downloadedCur,
|
|
|
|
torrent->corruptCur,
|
2009-01-02 17:01:55 +00:00
|
|
|
tr_cpLeftUntilComplete( &torrent->completion ),
|
2008-12-02 18:24:26 +00:00
|
|
|
numwant,
|
|
|
|
t->key_param );
|
|
|
|
|
|
|
|
if( eventName && *eventName )
|
|
|
|
evbuffer_add_printf( buf, "&event=%s", eventName );
|
|
|
|
|
|
|
|
if( t->trackerID && *t->trackerID )
|
|
|
|
evbuffer_add_printf( buf, "&trackerid=%s", t->trackerID );
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
}
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static struct tr_tracker_request*
|
2008-12-02 19:46:51 +00:00
|
|
|
createRequest( tr_session * session,
|
|
|
|
tr_tracker * tracker,
|
|
|
|
int reqtype )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2008-12-02 19:46:51 +00:00
|
|
|
static const char* strings[] = { "started", "completed", "stopped", "paused", "", "err" };
|
|
|
|
const tr_torrent * torrent = tr_torrentFindFromHash( session, tracker->hash );
|
|
|
|
const tr_tracker_info * address = getCurrentAddressFromTorrent( tracker, torrent );
|
|
|
|
int isStopping;
|
2007-11-29 00:43:58 +00:00
|
|
|
struct tr_tracker_request * req;
|
2008-12-02 19:46:51 +00:00
|
|
|
struct evbuffer * url;
|
|
|
|
|
|
|
|
/* BEP 21: In order to tell the tracker that a peer is a partial seed, it MUST send
|
|
|
|
* an event=paused parameter in every announce while it is a partial seed. */
|
2009-01-02 17:01:55 +00:00
|
|
|
if( tr_cpGetStatus( &torrent->completion ) == TR_PARTIAL_SEED )
|
2008-12-02 19:46:51 +00:00
|
|
|
reqtype = TR_REQ_PAUSED;
|
|
|
|
|
|
|
|
isStopping = reqtype == TR_REQ_STOPPED;
|
2008-04-24 01:42:53 +00:00
|
|
|
|
|
|
|
url = evbuffer_new( );
|
|
|
|
evbuffer_add_printf( url, "%s", address->announce );
|
|
|
|
buildTrackerRequestURI( tracker, torrent, strings[reqtype], url );
|
2007-11-29 00:43:58 +00:00
|
|
|
|
|
|
|
req = tr_new0( struct tr_tracker_request, 1 );
|
2008-04-24 01:42:53 +00:00
|
|
|
req->session = session;
|
2007-11-30 17:10:33 +00:00
|
|
|
req->reqtype = reqtype;
|
2008-04-24 01:42:53 +00:00
|
|
|
req->done_func = isStopping ? onStoppedResponse : onTrackerResponse;
|
2008-12-30 00:56:10 +00:00
|
|
|
req->url = url;
|
2008-12-29 21:17:48 +00:00
|
|
|
req->torrentId = tracker->torrentId;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
|
|
|
return req;
|
|
|
|
}
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static struct tr_tracker_request*
|
2008-09-23 19:11:04 +00:00
|
|
|
createScrape( tr_session * session,
|
|
|
|
tr_tracker * tracker )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
const tr_tracker_info * a = getCurrentAddress( tracker );
|
2007-11-29 00:43:58 +00:00
|
|
|
struct tr_tracker_request * req;
|
2008-09-23 19:11:04 +00:00
|
|
|
struct evbuffer * url = evbuffer_new( );
|
2008-04-24 01:42:53 +00:00
|
|
|
|
|
|
|
evbuffer_add_printf( url, "%s%cinfo_hash=%s",
|
2008-09-23 19:11:04 +00:00
|
|
|
a->scrape, strchr( a->scrape, '?' ) ? '&' : '?',
|
|
|
|
tracker->escaped );
|
2007-11-29 00:43:58 +00:00
|
|
|
|
|
|
|
req = tr_new0( struct tr_tracker_request, 1 );
|
2008-04-24 01:42:53 +00:00
|
|
|
req->session = session;
|
2007-11-30 17:10:33 +00:00
|
|
|
req->reqtype = TR_REQ_SCRAPE;
|
2008-12-30 00:56:10 +00:00
|
|
|
req->url = url;
|
2008-04-24 01:42:53 +00:00
|
|
|
req->done_func = onScrapeResponse;
|
2008-12-29 21:17:48 +00:00
|
|
|
req->torrentId = tracker->torrentId;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
|
|
|
return req;
|
|
|
|
}
|
2006-12-02 01:46:54 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
struct tr_tracker_handle
|
|
|
|
{
|
2009-02-04 18:54:29 +00:00
|
|
|
tr_bool shutdownHint;
|
2008-09-23 19:11:04 +00:00
|
|
|
int runningCount;
|
|
|
|
tr_timer * pulseTimer;
|
2007-11-29 00:43:58 +00:00
|
|
|
};
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2008-07-28 19:47:16 +00:00
|
|
|
static int trackerPulse( void * vsession );
|
2006-12-02 01:46:54 +00:00
|
|
|
|
2009-02-04 16:58:52 +00:00
|
|
|
void
|
|
|
|
tr_trackerSessionInit( tr_session * session )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2009-02-04 16:58:52 +00:00
|
|
|
assert( tr_isSession( session ) );
|
|
|
|
|
|
|
|
session->tracker = tr_new0( struct tr_tracker_handle, 1 );
|
|
|
|
session->tracker->pulseTimer = tr_timerNew( session, trackerPulse, session, PULSE_INTERVAL_MSEC );
|
|
|
|
dbgmsg( NULL, "creating tracker timer" );
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
2006-12-02 01:46:54 +00:00
|
|
|
|
2007-11-29 02:31:21 +00:00
|
|
|
void
|
2008-07-31 13:06:59 +00:00
|
|
|
tr_trackerSessionClose( tr_session * session )
|
2009-02-04 18:54:29 +00:00
|
|
|
{
|
|
|
|
assert( tr_isSession( session ) );
|
|
|
|
|
|
|
|
session->tracker->shutdownHint = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
tr_trackerSessionDestroy( tr_session * session )
|
2007-11-29 02:31:21 +00:00
|
|
|
{
|
2008-07-31 13:06:59 +00:00
|
|
|
if( session && session->tracker )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
|
|
|
dbgmsg( NULL, "freeing tracker timer" );
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_timerFree( &session->tracker->pulseTimer );
|
|
|
|
tr_free( session->tracker );
|
|
|
|
session->tracker = NULL;
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
2007-08-16 20:00:06 +00:00
|
|
|
}
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
2007-08-20 02:29:36 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
static void
|
2008-04-24 01:42:53 +00:00
|
|
|
invokeRequest( void * vreq )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
struct tr_tracker_request * req = vreq;
|
2009-02-04 17:38:40 +00:00
|
|
|
tr_tracker * t;
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2009-02-04 17:38:40 +00:00
|
|
|
assert( req != NULL );
|
|
|
|
assert( tr_isSession( req->session ) );
|
|
|
|
assert( req->torrentId >= 0 );
|
|
|
|
assert( req->reqtype >= 0 );
|
|
|
|
assert( req->reqtype < TR_NUM_REQ_TYPES );
|
|
|
|
|
2009-02-04 18:19:37 +00:00
|
|
|
dbgmsg( NULL, "invokeRequest got session %p, tracker %p", req->session, req->session->tracker );
|
|
|
|
|
2009-02-04 17:38:40 +00:00
|
|
|
t = findTracker( req->session, req->torrentId );
|
|
|
|
|
|
|
|
if( t != NULL )
|
2008-02-21 07:29:39 +00:00
|
|
|
{
|
2008-04-25 16:40:14 +00:00
|
|
|
const time_t now = time( NULL );
|
|
|
|
|
2008-02-21 07:29:39 +00:00
|
|
|
if( req->reqtype == TR_REQ_SCRAPE )
|
|
|
|
{
|
2008-04-25 16:40:14 +00:00
|
|
|
t->lastScrapeTime = now;
|
2008-10-15 16:43:51 +00:00
|
|
|
t->scrapeAt = TR_TRACKER_BUSY;
|
2008-02-21 07:29:39 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-04-25 16:40:14 +00:00
|
|
|
t->lastAnnounceTime = now;
|
2008-10-15 16:43:51 +00:00
|
|
|
t->reannounceAt = TR_TRACKER_BUSY;
|
|
|
|
t->manualAnnounceAllowedAt = TR_TRACKER_BUSY;
|
2008-02-21 07:29:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-04 17:38:40 +00:00
|
|
|
assert( req->session->tracker != NULL );
|
2008-04-24 01:42:53 +00:00
|
|
|
++req->session->tracker->runningCount;
|
2007-09-25 18:39:58 +00:00
|
|
|
|
2008-12-30 00:56:10 +00:00
|
|
|
tr_webRun( req->session,
|
|
|
|
(char*)EVBUFFER_DATA(req->url),
|
|
|
|
NULL,
|
2008-12-29 21:17:48 +00:00
|
|
|
req->done_func, tr_int2ptr( req->torrentId ) );
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
freeRequest( req );
|
2007-12-27 22:38:53 +00:00
|
|
|
}
|
|
|
|
|
2007-11-30 17:10:33 +00:00
|
|
|
static void
|
2008-09-23 19:11:04 +00:00
|
|
|
enqueueScrape( tr_session * session,
|
|
|
|
tr_tracker * tracker )
|
2007-11-30 17:10:33 +00:00
|
|
|
{
|
2009-02-04 17:38:40 +00:00
|
|
|
struct tr_tracker_request * req;
|
|
|
|
assert( tr_isSession( session ) );
|
|
|
|
|
|
|
|
req = createScrape( session, tracker );
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_runInEventThread( session, invokeRequest, req );
|
2007-11-30 17:10:33 +00:00
|
|
|
}
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static void
|
2008-09-23 19:11:04 +00:00
|
|
|
enqueueRequest( tr_session * session,
|
|
|
|
tr_tracker * tracker,
|
|
|
|
int reqtype )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2009-02-04 17:38:40 +00:00
|
|
|
struct tr_tracker_request * req;
|
|
|
|
assert( tr_isSession( session ) );
|
|
|
|
|
|
|
|
req = createRequest( session, tracker, reqtype );
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_runInEventThread( session, invokeRequest, req );
|
2008-01-19 00:28:52 +00:00
|
|
|
}
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static int
|
2008-07-28 19:47:16 +00:00
|
|
|
trackerPulse( void * vsession )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
tr_session * session = vsession;
|
2008-04-24 01:42:53 +00:00
|
|
|
struct tr_tracker_handle * th = session->tracker;
|
2008-09-23 19:11:04 +00:00
|
|
|
tr_torrent * tor;
|
|
|
|
const time_t now = time( NULL );
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2009-02-04 18:54:29 +00:00
|
|
|
if( !th )
|
2007-12-13 21:48:39 +00:00
|
|
|
return FALSE;
|
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if( th->runningCount )
|
|
|
|
dbgmsg( NULL, "tracker pulse... %d running", th->runningCount );
|
2007-11-29 00:43:58 +00:00
|
|
|
|
|
|
|
/* upkeep: queue periodic rescrape / reannounce */
|
2009-01-13 16:51:38 +00:00
|
|
|
tor = NULL;
|
|
|
|
while(( tor = tr_torrentNext( session, tor )))
|
2007-11-30 17:10:33 +00:00
|
|
|
{
|
|
|
|
tr_tracker * t = tor->tracker;
|
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
if( ( t->scrapeAt > 1 )
|
|
|
|
&& ( t->scrapeAt <= now )
|
|
|
|
&& ( trackerSupportsScrape( t, tor ) ) )
|
2008-07-11 11:51:15 +00:00
|
|
|
{
|
2008-10-15 16:43:51 +00:00
|
|
|
t->scrapeAt = TR_TRACKER_BUSY;
|
2008-04-24 01:42:53 +00:00
|
|
|
enqueueScrape( session, t );
|
2007-11-30 17:10:33 +00:00
|
|
|
}
|
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
if( ( t->reannounceAt > 1 )
|
|
|
|
&& ( t->reannounceAt <= now )
|
|
|
|
&& ( t->isRunning ) )
|
2008-07-11 11:51:15 +00:00
|
|
|
{
|
2008-10-15 16:43:51 +00:00
|
|
|
t->reannounceAt = TR_TRACKER_BUSY;
|
|
|
|
t->manualAnnounceAllowedAt = TR_TRACKER_BUSY;
|
2008-04-24 01:42:53 +00:00
|
|
|
enqueueRequest( session, t, TR_REQ_REANNOUNCE );
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
|
|
|
}
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if( th->runningCount )
|
2008-09-23 19:11:04 +00:00
|
|
|
dbgmsg( NULL, "tracker pulse after upkeep... %d running",
|
|
|
|
th->runningCount );
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-07-31 13:06:59 +00:00
|
|
|
/* free the tracker manager if no torrents are left */
|
2009-02-04 18:54:29 +00:00
|
|
|
if( ( th != NULL )
|
|
|
|
&& ( th->shutdownHint != FALSE )
|
|
|
|
&& ( th->runningCount < 1 )
|
|
|
|
&& ( tr_sessionCountTorrents( session ) == 0 ) )
|
2008-07-31 13:06:59 +00:00
|
|
|
{
|
2009-02-04 18:54:29 +00:00
|
|
|
tr_trackerSessionDestroy( session );
|
|
|
|
return FALSE;
|
2008-07-31 13:06:59 +00:00
|
|
|
}
|
|
|
|
|
2009-02-04 18:54:29 +00:00
|
|
|
return TRUE;
|
2007-11-29 00:43:58 +00:00
|
|
|
}
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2007-12-05 02:06:05 +00:00
|
|
|
static void
|
2008-04-24 01:42:53 +00:00
|
|
|
onReqDone( tr_session * session )
|
2007-12-05 02:06:05 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
if( session->tracker )
|
2007-12-13 21:48:39 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
--session->tracker->runningCount;
|
2008-09-23 19:11:04 +00:00
|
|
|
dbgmsg( NULL, "decrementing runningCount to %d",
|
|
|
|
session->tracker->runningCount );
|
2008-07-28 19:47:16 +00:00
|
|
|
trackerPulse( session );
|
2007-12-13 21:48:39 +00:00
|
|
|
}
|
2007-12-05 02:06:05 +00:00
|
|
|
}
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
/***
|
|
|
|
**** LIFE CYCLE
|
|
|
|
***/
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static void
|
2008-09-23 19:11:04 +00:00
|
|
|
generateKeyParam( char * msg,
|
|
|
|
int len )
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
int i;
|
2007-11-29 00:43:58 +00:00
|
|
|
const char * pool = "abcdefghijklmnopqrstuvwxyz0123456789";
|
2008-09-23 19:11:04 +00:00
|
|
|
const int poolSize = strlen( pool );
|
|
|
|
|
|
|
|
for( i = 0; i < len; ++i )
|
|
|
|
*msg++ = pool[tr_cryptoRandInt( poolSize )];
|
2007-11-29 00:43:58 +00:00
|
|
|
*msg = '\0';
|
|
|
|
}
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2008-01-03 17:49:45 +00:00
|
|
|
static int
|
|
|
|
is_rfc2396_alnum( char ch )
|
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
return ( '0' <= ch && ch <= '9' )
|
|
|
|
|| ( 'A' <= ch && ch <= 'Z' )
|
|
|
|
|| ( 'a' <= ch && ch <= 'z' );
|
2008-01-03 17:49:45 +00:00
|
|
|
}
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static void
|
2008-09-23 19:11:04 +00:00
|
|
|
escape( char * out,
|
|
|
|
const uint8_t * in,
|
|
|
|
int in_len ) /* rfc2396 */
|
2007-11-29 00:43:58 +00:00
|
|
|
{
|
|
|
|
const uint8_t *end = in + in_len;
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
while( in != end )
|
2008-09-23 19:11:04 +00:00
|
|
|
if( is_rfc2396_alnum( *in ) )
|
2007-11-29 00:43:58 +00:00
|
|
|
*out++ = (char) *in++;
|
2008-09-23 19:11:04 +00:00
|
|
|
else
|
2008-07-15 17:16:57 +00:00
|
|
|
out += tr_snprintf( out, 4, "%%%02X", (unsigned int)*in++ );
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
*out = '\0';
|
|
|
|
}
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
tr_tracker *
|
|
|
|
tr_trackerNew( const tr_torrent * torrent )
|
|
|
|
{
|
|
|
|
const tr_info * info = &torrent->info;
|
2008-09-23 19:11:04 +00:00
|
|
|
tr_tracker * t;
|
2007-10-18 03:55:55 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
t = tr_new0( tr_tracker, 1 );
|
2008-12-29 18:10:07 +00:00
|
|
|
t->publisher = TR_PUBLISHER_INIT;
|
2008-10-02 15:53:33 +00:00
|
|
|
t->session = torrent->session;
|
2008-04-24 01:42:53 +00:00
|
|
|
t->scrapeIntervalSec = DEFAULT_SCRAPE_INTERVAL_SEC;
|
2008-06-24 21:39:07 +00:00
|
|
|
t->retryScrapeIntervalSec = FIRST_SCRAPE_RETRY_INTERVAL_SEC;
|
|
|
|
t->retryAnnounceIntervalSec = FIRST_ANNOUNCE_RETRY_INTERVAL_SEC;
|
2008-04-24 01:42:53 +00:00
|
|
|
t->announceIntervalSec = DEFAULT_ANNOUNCE_INTERVAL_SEC;
|
|
|
|
t->announceMinIntervalSec = DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC;
|
|
|
|
t->timesDownloaded = -1;
|
|
|
|
t->seederCount = -1;
|
2008-12-02 19:46:51 +00:00
|
|
|
t->downloaderCount = -1;
|
2008-04-24 01:42:53 +00:00
|
|
|
t->leecherCount = -1;
|
2008-04-25 04:35:06 +00:00
|
|
|
t->lastAnnounceResponse = -1;
|
|
|
|
t->lastScrapeResponse = -1;
|
2008-04-24 01:42:53 +00:00
|
|
|
t->manualAnnounceAllowedAt = ~(time_t)0;
|
2008-12-29 21:17:48 +00:00
|
|
|
t->name = tr_strdup( info->name );
|
|
|
|
t->torrentId = torrent->uniqueId;
|
|
|
|
t->randOffset = tr_cryptoRandInt( 30 );
|
2007-11-29 00:43:58 +00:00
|
|
|
memcpy( t->hash, info->hash, SHA_DIGEST_LENGTH );
|
|
|
|
escape( t->escaped, info->hash, SHA_DIGEST_LENGTH );
|
2008-04-24 01:42:53 +00:00
|
|
|
generateKeyParam( t->key_param, KEYLEN );
|
2007-10-18 03:55:55 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
t->trackerIndex = 0;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
if( trackerSupportsScrape( t, torrent ) )
|
|
|
|
t->scrapeAt = time( NULL ) + t->randOffset;
|
2007-11-29 00:43:58 +00:00
|
|
|
|
|
|
|
return t;
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
static void
|
|
|
|
onTrackerFreeNow( void * vt )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_tracker * t = vt;
|
2007-10-04 19:58:30 +00:00
|
|
|
|
2008-12-29 18:10:07 +00:00
|
|
|
tr_publisherDestruct( &t->publisher );
|
2007-11-29 00:43:58 +00:00
|
|
|
tr_free( t->name );
|
|
|
|
tr_free( t->trackerID );
|
2008-01-07 06:19:34 +00:00
|
|
|
tr_free( t->peer_id );
|
2007-08-16 20:00:06 +00:00
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
tr_free( t );
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2008-04-15 15:51:59 +00:00
|
|
|
/***
|
|
|
|
**** PUBLIC
|
|
|
|
***/
|
|
|
|
|
2007-11-29 00:43:58 +00:00
|
|
|
void
|
|
|
|
tr_trackerFree( tr_tracker * t )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2008-04-15 15:51:59 +00:00
|
|
|
if( t )
|
2008-04-24 01:42:53 +00:00
|
|
|
tr_runInEventThread( t->session, onTrackerFreeNow, t );
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
2006-12-02 01:46:54 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
tr_publisher_tag
|
2008-09-23 19:11:04 +00:00
|
|
|
tr_trackerSubscribe( tr_tracker * t,
|
|
|
|
tr_delivery_func func,
|
|
|
|
void * user_data )
|
2006-12-02 01:46:54 +00:00
|
|
|
{
|
2008-12-29 18:10:07 +00:00
|
|
|
return tr_publisherSubscribe( &t->publisher, func, user_data );
|
2006-12-02 01:46:54 +00:00
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
void
|
2008-09-23 19:11:04 +00:00
|
|
|
tr_trackerUnsubscribe( tr_tracker * t,
|
|
|
|
tr_publisher_tag tag )
|
2006-12-17 16:36:27 +00:00
|
|
|
{
|
2008-04-15 15:51:59 +00:00
|
|
|
if( t )
|
2008-12-29 18:10:07 +00:00
|
|
|
tr_publisherUnsubscribe( &t->publisher, tag );
|
2006-12-17 16:36:27 +00:00
|
|
|
}
|
|
|
|
|
2007-09-20 16:32:01 +00:00
|
|
|
const tr_tracker_info *
|
2009-01-03 23:11:29 +00:00
|
|
|
tr_trackerGetAddress( tr_tracker * t, const tr_torrent * torrent )
|
2006-12-17 16:36:27 +00:00
|
|
|
{
|
2009-01-03 23:11:29 +00:00
|
|
|
return getCurrentAddressFromTorrent( t, torrent );
|
2006-12-17 16:36:27 +00:00
|
|
|
}
|
|
|
|
|
2008-02-09 17:07:30 +00:00
|
|
|
time_t
|
|
|
|
tr_trackerGetManualAnnounceTime( const struct tr_tracker * t )
|
|
|
|
{
|
|
|
|
return t->isRunning ? t->manualAnnounceAllowedAt : 0;
|
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
int
|
2008-09-23 19:11:04 +00:00
|
|
|
tr_trackerCanManualAnnounce( const tr_tracker * t )
|
2007-07-12 20:48:13 +00:00
|
|
|
{
|
2008-02-09 17:07:30 +00:00
|
|
|
const time_t allow = tr_trackerGetManualAnnounceTime( t );
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2008-02-09 17:07:30 +00:00
|
|
|
return allow && ( allow <= time( NULL ) );
|
2007-07-12 20:48:13 +00:00
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
void
|
2008-09-23 19:11:04 +00:00
|
|
|
tr_trackerGetCounts( const tr_tracker * t,
|
2008-12-02 19:46:51 +00:00
|
|
|
int * setme_completedCount,
|
|
|
|
int * setme_leecherCount,
|
|
|
|
int * setme_seederCount,
|
|
|
|
int * setme_downloaderCount )
|
2006-12-02 01:46:54 +00:00
|
|
|
{
|
2007-08-20 02:29:36 +00:00
|
|
|
if( setme_completedCount )
|
2008-09-23 19:11:04 +00:00
|
|
|
*setme_completedCount = t->timesDownloaded;
|
2006-12-02 01:46:54 +00:00
|
|
|
|
2007-08-20 02:29:36 +00:00
|
|
|
if( setme_leecherCount )
|
2008-09-23 19:11:04 +00:00
|
|
|
*setme_leecherCount = t->leecherCount;
|
2006-12-02 01:46:54 +00:00
|
|
|
|
2007-08-20 02:29:36 +00:00
|
|
|
if( setme_seederCount )
|
2008-09-23 19:11:04 +00:00
|
|
|
*setme_seederCount = t->seederCount;
|
2008-12-02 19:46:51 +00:00
|
|
|
|
|
|
|
if( setme_downloaderCount )
|
|
|
|
*setme_downloaderCount = t->downloaderCount;
|
2006-12-02 01:46:54 +00:00
|
|
|
}
|
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
void
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_trackerStart( tr_tracker * t )
|
2006-12-02 01:46:54 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
if( t && !t->isRunning )
|
2008-04-15 15:51:59 +00:00
|
|
|
{
|
2008-12-04 05:27:59 +00:00
|
|
|
tr_torrent * tor;
|
|
|
|
|
|
|
|
/* change the peer-id */
|
2008-04-15 15:51:59 +00:00
|
|
|
tr_free( t->peer_id );
|
|
|
|
t->peer_id = tr_peerIdNew( );
|
2008-12-04 05:27:59 +00:00
|
|
|
if(( tor = tr_torrentFindFromHash( t->session, t->hash ))) {
|
|
|
|
tr_free( tor->peer_id );
|
|
|
|
tor->peer_id = (uint8_t*) tr_strdup( t->peer_id );
|
|
|
|
}
|
2008-01-07 06:19:34 +00:00
|
|
|
|
2008-04-24 01:42:53 +00:00
|
|
|
t->isRunning = 1;
|
|
|
|
enqueueRequest( t->session, t, TR_REQ_STARTED );
|
2007-10-04 19:58:30 +00:00
|
|
|
}
|
2006-12-02 01:46:54 +00:00
|
|
|
}
|
2007-01-27 21:17:10 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
void
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_trackerReannounce( tr_tracker * t )
|
2007-01-27 21:17:10 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
enqueueRequest( t->session, t, TR_REQ_REANNOUNCE );
|
2007-01-27 21:17:10 +00:00
|
|
|
}
|
2007-03-30 00:12:39 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
void
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_trackerCompleted( tr_tracker * t )
|
2007-03-30 00:12:39 +00:00
|
|
|
{
|
2008-04-24 01:42:53 +00:00
|
|
|
enqueueRequest( t->session, t, TR_REQ_COMPLETED );
|
2007-08-16 20:00:06 +00:00
|
|
|
}
|
2007-03-30 00:12:39 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
void
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_trackerStop( tr_tracker * t )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
if( t && t->isRunning )
|
|
|
|
{
|
2007-10-17 18:59:58 +00:00
|
|
|
t->isRunning = 0;
|
2008-10-15 16:43:51 +00:00
|
|
|
t->reannounceAt = TR_TRACKER_STOPPED;
|
|
|
|
t->manualAnnounceAllowedAt = TR_TRACKER_STOPPED;
|
2008-04-24 01:42:53 +00:00
|
|
|
enqueueRequest( t->session, t, TR_REQ_STOPPED );
|
2007-10-04 19:58:30 +00:00
|
|
|
}
|
2007-08-16 20:00:06 +00:00
|
|
|
}
|
2007-03-30 00:12:39 +00:00
|
|
|
|
2007-08-16 20:00:06 +00:00
|
|
|
void
|
2007-10-17 18:59:58 +00:00
|
|
|
tr_trackerChangeMyPort( tr_tracker * t )
|
2007-08-16 20:00:06 +00:00
|
|
|
{
|
2007-10-17 18:59:58 +00:00
|
|
|
if( t->isRunning )
|
|
|
|
tr_trackerReannounce( t );
|
2007-03-30 00:12:39 +00:00
|
|
|
}
|
2008-02-21 07:29:39 +00:00
|
|
|
|
|
|
|
void
|
2008-05-22 23:11:21 +00:00
|
|
|
tr_trackerStat( const tr_tracker * t,
|
2008-09-23 19:11:04 +00:00
|
|
|
struct tr_stat * setme )
|
2008-02-21 07:29:39 +00:00
|
|
|
{
|
2008-04-25 04:26:04 +00:00
|
|
|
assert( t );
|
|
|
|
assert( setme );
|
2008-02-21 07:29:39 +00:00
|
|
|
|
|
|
|
setme->lastScrapeTime = t->lastScrapeTime;
|
|
|
|
setme->nextScrapeTime = t->scrapeAt;
|
|
|
|
setme->lastAnnounceTime = t->lastAnnounceTime;
|
|
|
|
setme->nextAnnounceTime = t->reannounceAt;
|
2008-05-22 23:11:21 +00:00
|
|
|
setme->manualAnnounceTime = t->manualAnnounceAllowedAt;
|
2008-04-25 04:35:06 +00:00
|
|
|
|
|
|
|
if( t->lastScrapeResponse == -1 ) /* never been scraped */
|
|
|
|
*setme->scrapeResponse = '\0';
|
|
|
|
else
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( setme->scrapeResponse,
|
|
|
|
sizeof( setme->scrapeResponse ),
|
|
|
|
"%s (%ld)",
|
|
|
|
tr_webGetResponseStr( t->lastScrapeResponse ),
|
|
|
|
t->lastScrapeResponse );
|
2008-04-25 04:35:06 +00:00
|
|
|
|
|
|
|
if( t->lastAnnounceResponse == -1 ) /* never been announced */
|
|
|
|
*setme->announceResponse = '\0';
|
|
|
|
else
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( setme->announceResponse,
|
|
|
|
sizeof( setme->announceResponse ),
|
|
|
|
"%s (%ld)",
|
|
|
|
tr_webGetResponseStr( t->lastAnnounceResponse ),
|
|
|
|
t->lastAnnounceResponse );
|
2008-02-21 07:29:39 +00:00
|
|
|
}
|
2008-09-23 19:11:04 +00:00
|
|
|
|