mirror of
https://github.com/transmission/transmission
synced 2024-12-26 01:27:28 +00:00
be more forgiving of tracker failure
This commit is contained in:
parent
0a7708e0a8
commit
f2a08d272f
1 changed files with 98 additions and 43 deletions
|
@ -35,7 +35,7 @@
|
|||
enum
|
||||
{
|
||||
/* seconds between tracker pulses */
|
||||
PULSE_INTERVAL_SEC = 1,
|
||||
PULSE_INTERVAL_MSEC = 750,
|
||||
|
||||
/* maximum number of concurrent tracker socket connections */
|
||||
MAX_TRACKER_SOCKETS = 16,
|
||||
|
@ -67,15 +67,6 @@ enum
|
|||
***
|
||||
**/
|
||||
|
||||
enum
|
||||
{
|
||||
TR_REQ_STARTED,
|
||||
TR_REQ_COMPLETED,
|
||||
TR_REQ_STOPPED,
|
||||
TR_REQ_REANNOUNCE,
|
||||
TR_REQ_COUNT
|
||||
};
|
||||
|
||||
struct tr_tracker
|
||||
{
|
||||
tr_handle * handle;
|
||||
|
@ -116,15 +107,13 @@ struct tr_tracker
|
|||
int leecherCount;
|
||||
char * trackerID;
|
||||
|
||||
/* the last tracker request we sent. (started, stopped, etc.)
|
||||
automatic announces are an empty string;
|
||||
NULL means no message has ever been sent */
|
||||
char * lastRequest;
|
||||
|
||||
time_t manualAnnounceAllowedAt;
|
||||
time_t reannounceAt;
|
||||
time_t scrapeAt;
|
||||
|
||||
time_t resendRequestAt;
|
||||
int resendRequestType;
|
||||
|
||||
unsigned int isRunning : 1;
|
||||
};
|
||||
|
||||
|
@ -210,6 +199,13 @@ findTrackerFromHash( struct torrent_hash * data )
|
|||
return torrent ? torrent->tracker : NULL;
|
||||
}
|
||||
|
||||
tr_tracker *
|
||||
findTracker( tr_handle * handle, const uint8_t * hash )
|
||||
{
|
||||
tr_torrent * torrent = tr_torrentFindFromHash( handle, hash );
|
||||
return torrent ? torrent->tracker : NULL;
|
||||
}
|
||||
|
||||
/***
|
||||
**** PUBLISH
|
||||
***/
|
||||
|
@ -540,9 +536,10 @@ onScrapeResponse( struct evhttp_request * req, void * vhash )
|
|||
{
|
||||
const char * warning;
|
||||
time_t nextScrapeSec = 60;
|
||||
tr_tracker * t;
|
||||
tr_tracker * t = findTrackerFromHash( vhash );
|
||||
|
||||
dbgmsg( t, "Got scrape response for '%s': %s", (t ? t->name : "(null)"), (req ? req->response_code_line : "(no line)") );
|
||||
|
||||
t = findTrackerFromHash( vhash );
|
||||
tr_free( vhash );
|
||||
if( t == NULL ) /* tracker's been closed... */
|
||||
return;
|
||||
|
@ -610,13 +607,25 @@ onScrapeResponse( struct evhttp_request * req, void * vhash )
|
|||
****
|
||||
***/
|
||||
|
||||
enum
|
||||
{
|
||||
TR_REQ_STARTED,
|
||||
TR_REQ_COMPLETED,
|
||||
TR_REQ_STOPPED,
|
||||
TR_REQ_REANNOUNCE,
|
||||
TR_REQ_SCRAPE,
|
||||
TR_REQ_COUNT
|
||||
};
|
||||
|
||||
struct tr_tracker_request
|
||||
{
|
||||
int port;
|
||||
int timeout;
|
||||
int reqtype; /* TR_REQ_* */
|
||||
char * address;
|
||||
char * uri;
|
||||
struct evhttp_request * req;
|
||||
uint8_t torrent_hash[SHA_DIGEST_LENGTH];
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -693,7 +702,7 @@ buildTrackerRequestURI( const tr_tracker * t,
|
|||
static struct tr_tracker_request*
|
||||
createRequest( tr_handle * handle, const tr_tracker * tracker, int reqtype )
|
||||
{
|
||||
static const char* strings[TR_REQ_COUNT] = { "started", "completed", "stopped", "" };
|
||||
static const char* strings[TR_REQ_COUNT] = { "started", "completed", "stopped", "", "err" };
|
||||
const tr_torrent * torrent = tr_torrentFindFromHash( handle, tracker->hash );
|
||||
const tr_tracker_info * address = getCurrentAddress( tracker );
|
||||
const int isStopping = reqtype == TR_REQ_STOPPED;
|
||||
|
@ -705,9 +714,11 @@ createRequest( tr_handle * handle, const tr_tracker * tracker, int reqtype )
|
|||
req->port = address->port;
|
||||
req->uri = buildTrackerRequestURI( tracker, torrent, eventName );
|
||||
req->timeout = isStopping ? STOP_TIMEOUT_INTERVAL_SEC : TIMEOUT_INTERVAL_SEC;
|
||||
req->reqtype = reqtype;
|
||||
req->req = isStopping
|
||||
? evhttp_request_new( onStoppedResponse, handle )
|
||||
: evhttp_request_new( onTrackerResponse, torrentHashNew(handle, tracker) );
|
||||
memcpy( req->torrent_hash, tracker->hash, SHA_DIGEST_LENGTH );
|
||||
addCommonHeaders( tracker, req->req );
|
||||
|
||||
return req;
|
||||
|
@ -724,7 +735,9 @@ createScrape( tr_handle * handle, const tr_tracker * tracker )
|
|||
req->port = a->port;
|
||||
req->timeout = TIMEOUT_INTERVAL_SEC;
|
||||
req->req = evhttp_request_new( onScrapeResponse, torrentHashNew( handle, tracker ) );
|
||||
req->reqtype = TR_REQ_SCRAPE;
|
||||
tr_asprintf( &req->uri, "%s%cinfo_hash=%s", a->scrape, strchr(a->scrape,'?')?'&':'?', tracker->escaped );
|
||||
memcpy( req->torrent_hash, tracker->hash, SHA_DIGEST_LENGTH );
|
||||
addCommonHeaders( tracker, req->req );
|
||||
|
||||
return req;
|
||||
|
@ -746,7 +759,7 @@ ensureGlobalsExist( tr_handle * handle )
|
|||
if( handle->tracker == NULL )
|
||||
{
|
||||
handle->tracker = tr_new0( struct tr_tracker_handle, 1 );
|
||||
handle->tracker->pulseTimer = tr_timerNew( handle, pulse, handle, PULSE_INTERVAL_SEC*1000 );
|
||||
handle->tracker->pulseTimer = tr_timerNew( handle, pulse, handle, PULSE_INTERVAL_MSEC );
|
||||
dbgmsg( NULL, "creating tracker timer" );
|
||||
}
|
||||
}
|
||||
|
@ -821,21 +834,44 @@ getConnection( tr_handle * handle, const char * address, int port )
|
|||
return c;
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
invokeRequest( tr_handle * handle, const struct tr_tracker_request * req )
|
||||
{
|
||||
int err;
|
||||
struct evhttp_connection * evcon = getConnection( handle, req->address, req->port );
|
||||
++handle->tracker->socketCount;
|
||||
dbgmsg( NULL, "incrementing socket count to %d, sending '%s' to tracker %s:%d", handle->tracker->socketCount, req->uri, req->address, req->port );
|
||||
dbgmsg( NULL, "sending '%s' to tracker %s:%d, timeout is %d", req->uri, req->address, req->port, (int)req->timeout );
|
||||
evhttp_connection_set_timeout( evcon, req->timeout );
|
||||
evhttp_make_request( evcon, req->req, EVHTTP_REQ_GET, req->uri );
|
||||
err = evhttp_make_request( evcon, req->req, EVHTTP_REQ_GET, req->uri );
|
||||
if( !err ) {
|
||||
++handle->tracker->socketCount;
|
||||
dbgmsg( NULL, "incremented socket count to %d", handle->tracker->socketCount );
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void
|
||||
invokeNextInQueue( tr_handle * handle, tr_list ** list )
|
||||
{
|
||||
struct tr_tracker_request * req = tr_list_pop_front( list );
|
||||
invokeRequest( handle, req );
|
||||
const int err = invokeRequest( handle, req );
|
||||
|
||||
if( err )
|
||||
{
|
||||
tr_tracker * t = findTracker( handle, req->torrent_hash );
|
||||
if( t != NULL )
|
||||
{
|
||||
if( req->reqtype == TR_REQ_SCRAPE ) {
|
||||
t->scrapeAt = time(NULL) + 30;
|
||||
dbgmsg( t, "scrape failed... retrying in 30 seconds" );
|
||||
}
|
||||
else {
|
||||
dbgmsg( t, "request [%s] failed... retrying in 30 seconds", req->uri );
|
||||
t->resendRequestAt = time(NULL) + 30;
|
||||
t->resendRequestType = req->reqtype;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
freeRequest( req );
|
||||
}
|
||||
|
||||
|
@ -847,15 +883,6 @@ socketIsAvailable( tr_handle * handle )
|
|||
|
||||
static void ensureGlobalsExist( tr_handle * );
|
||||
|
||||
static void
|
||||
enqueueRequest( tr_handle * handle, const tr_tracker * tracker, int reqtype )
|
||||
{
|
||||
struct tr_tracker_request * req;
|
||||
ensureGlobalsExist( handle );
|
||||
req = createRequest( handle, tracker, reqtype );
|
||||
tr_list_append( &handle->tracker->requestQueue, req );
|
||||
}
|
||||
|
||||
static void
|
||||
enqueueScrape( tr_handle * handle, const tr_tracker * tracker )
|
||||
{
|
||||
|
@ -865,27 +892,56 @@ enqueueScrape( tr_handle * handle, const tr_tracker * tracker )
|
|||
tr_list_append( &handle->tracker->scrapeQueue, req );
|
||||
}
|
||||
|
||||
static void
|
||||
enqueueRequest( tr_handle * handle, const tr_tracker * tracker, int reqtype )
|
||||
{
|
||||
struct tr_tracker_request * req;
|
||||
ensureGlobalsExist( handle );
|
||||
req = createRequest( handle, tracker, reqtype );
|
||||
tr_list_append( &handle->tracker->requestQueue, req );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called when there's been an error invoking a request,
|
||||
* or when the tracker has returned back a server error that might require
|
||||
* the request to be re-sent.
|
||||
*/
|
||||
static void
|
||||
maybeRequeueRequest( tr_handle * handle, const tr_tracker * tracker, int reqtype )
|
||||
{
|
||||
/* FIXME */
|
||||
enqueueRequest( handle, tracker, reqtype );
|
||||
}
|
||||
|
||||
static int
|
||||
pulse( void * vhandle )
|
||||
{
|
||||
tr_handle * handle = vhandle;
|
||||
struct tr_tracker_handle * th = handle->tracker;
|
||||
tr_torrent * t;
|
||||
tr_torrent * tor;
|
||||
const time_t now = time( NULL );
|
||||
|
||||
if( handle->tracker->socketCount || tr_list_size(th->requestQueue) || tr_list_size(th->scrapeQueue) )
|
||||
dbgmsg( NULL, "tracker pulse... %d sockets, %d reqs left, %d scrapes left", handle->tracker->socketCount, tr_list_size(th->requestQueue), tr_list_size(th->scrapeQueue) );
|
||||
|
||||
/* upkeep: queue periodic rescrape / reannounce */
|
||||
for( t=handle->torrentList; t; t=t->next ) {
|
||||
tr_tracker * tracker = t->tracker;
|
||||
if( tracker->scrapeAt && trackerSupportsScrape( tracker ) && ( now >= tracker->scrapeAt ) ) {
|
||||
tracker->scrapeAt = 0;
|
||||
enqueueScrape( handle, tracker );
|
||||
for( tor=handle->torrentList; tor; tor=tor->next )
|
||||
{
|
||||
tr_tracker * t = tor->tracker;
|
||||
|
||||
if( t->resendRequestAt && ( now >= t->resendRequestAt ) ) {
|
||||
t->resendRequestAt = 0;
|
||||
maybeRequeueRequest( handle, t, t->resendRequestType );
|
||||
}
|
||||
if( tracker->reannounceAt && tracker->isRunning && ( now >= tracker->reannounceAt ) ) {
|
||||
tracker->reannounceAt = 0;
|
||||
enqueueRequest( handle, tracker, TR_REQ_REANNOUNCE );
|
||||
|
||||
if( t->scrapeAt && trackerSupportsScrape( t ) && ( now >= t->scrapeAt ) ) {
|
||||
t->scrapeAt = 0;
|
||||
enqueueScrape( handle, t );
|
||||
}
|
||||
|
||||
if( t->reannounceAt && t->isRunning && ( now >= t->reannounceAt ) ) {
|
||||
t->reannounceAt = 0;
|
||||
enqueueRequest( handle, t, TR_REQ_REANNOUNCE );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -999,7 +1055,6 @@ onTrackerFreeNow( void * vt )
|
|||
tr_publisherFree( &t->publisher );
|
||||
tr_free( t->name );
|
||||
tr_free( t->trackerID );
|
||||
tr_free( t->lastRequest );
|
||||
|
||||
/* addresses... */
|
||||
for( i=0; i<t->addressCount; ++i )
|
||||
|
|
Loading…
Reference in a new issue