take inspiration from Solomon when handling odd tracker errors that confuse tracker's request queue: stop the torrent.

when the tracker gives us errors that confuse the tracker work queue,
This commit is contained in:
Charles Kerr 2007-11-30 23:37:44 +00:00
parent fce835ceec
commit 0e1e7efd3b
2 changed files with 29 additions and 59 deletions

View File

@ -170,6 +170,7 @@ onTrackerResponse( void * tracker UNUSED, void * vevent, void * user_data )
tr_err( "Tracker: Error - %s", event->text ); tr_err( "Tracker: Error - %s", event->text );
tor->error = TR_ERROR_TC_ERROR; tor->error = TR_ERROR_TC_ERROR;
strlcpy( tor->errorString, event->text, sizeof(tor->errorString) ); strlcpy( tor->errorString, event->text, sizeof(tor->errorString) );
tr_torrentStop( tor );
break; break;
case TR_TRACKER_ERROR_CLEAR: case TR_TRACKER_ERROR_CLEAR:

View File

@ -35,7 +35,7 @@
enum enum
{ {
/* seconds between tracker pulses */ /* seconds between tracker pulses */
PULSE_INTERVAL_MSEC = 750, PULSE_INTERVAL_MSEC = 1000,
/* maximum number of concurrent tracker socket connections */ /* maximum number of concurrent tracker socket connections */
MAX_TRACKER_SOCKETS = 16, MAX_TRACKER_SOCKETS = 16,
@ -111,9 +111,6 @@ struct tr_tracker
time_t reannounceAt; time_t reannounceAt;
time_t scrapeAt; time_t scrapeAt;
time_t resendRequestAt;
int resendRequestType;
unsigned int isRunning : 1; unsigned int isRunning : 1;
}; };
@ -215,11 +212,14 @@ static const tr_tracker_event emptyEvent = { 0, NULL, NULL, NULL, 0 };
static void static void
publishMessage( tr_tracker * t, const char * msg, int type ) publishMessage( tr_tracker * t, const char * msg, int type )
{ {
tr_tracker_event event = emptyEvent; if( t != NULL )
event.hash = t->hash; {
event.messageType = type; tr_tracker_event event = emptyEvent;
event.text = msg; event.hash = t->hash;
tr_publisherPublish( t->publisher, t, &event ); event.messageType = type;
event.text = msg;
tr_publisherPublish( t->publisher, t, &event );
}
} }
static void static void
@ -229,8 +229,9 @@ publishErrorClear( tr_tracker * t )
} }
static void static void
publishErrorMessage( tr_tracker * t, const char * msg ) publishErrorMessageAndStop( tr_tracker * t, const char * msg )
{ {
t->isRunning = 0;
publishMessage( t, msg, TR_TRACKER_ERROR ); publishMessage( t, msg, TR_TRACKER_ERROR );
} }
@ -411,7 +412,7 @@ onTrackerResponse( struct evhttp_request * req, void * torrent_hash )
if(( tmp = tr_bencDictFind( &benc, "failure reason" ))) { if(( tmp = tr_bencDictFind( &benc, "failure reason" ))) {
dbgmsg( t, "got failure message [%s]", tmp->val.s.s ); dbgmsg( t, "got failure message [%s]", tmp->val.s.s );
publishErrorMessage( t, tmp->val.s.s ); publishErrorMessageAndStop( t, tmp->val.s.s );
} }
if(( tmp = tr_bencDictFind( &benc, "warning message" ))) { if(( tmp = tr_bencDictFind( &benc, "warning message" ))) {
@ -496,13 +497,15 @@ onTrackerResponse( struct evhttp_request * req, void * torrent_hash )
} }
else if( 400<=responseCode && responseCode<=499 ) else if( 400<=responseCode && responseCode<=499 )
{ {
dbgmsg( t, "got a 4xx error." ); const char * err = req && req->response_code_line
? req->response_code_line
: "Unspecified 4xx error from tracker.";
dbgmsg( t, err );
/* The request could not be understood by the server due to /* The request could not be understood by the server due to
* malformed syntax. The client SHOULD NOT repeat the * malformed syntax. The client SHOULD NOT repeat the
* request without modifications. */ * request without modifications. */
if( req && req->response_code_line ) publishErrorMessageAndStop( t, err );
publishErrorMessage( t, req->response_code_line );
t->manualAnnounceAllowedAt = ~(time_t)0; t->manualAnnounceAllowedAt = ~(time_t)0;
t->reannounceAt = 0; t->reannounceAt = 0;
} }
@ -525,7 +528,7 @@ onTrackerResponse( struct evhttp_request * req, void * torrent_hash )
/* WTF did we get?? */ /* WTF did we get?? */
if( req && req->response_code_line ) if( req && req->response_code_line )
publishErrorMessage( t, req->response_code_line ); publishWarning( t, req->response_code_line );
t->manualAnnounceAllowedAt = ~(time_t)0; t->manualAnnounceAllowedAt = ~(time_t)0;
t->reannounceAt = time(NULL) + 60; t->reannounceAt = time(NULL) + 60;
} }
@ -538,7 +541,7 @@ onScrapeResponse( struct evhttp_request * req, void * vhash )
time_t nextScrapeSec = 60; time_t nextScrapeSec = 60;
tr_tracker * t = findTrackerFromHash( vhash ); tr_tracker * t = findTrackerFromHash( vhash );
dbgmsg( t, "Got scrape response for '%s': %s", (t ? t->name : "(null)"), (req ? req->response_code_line : "(no line)") ); dbgmsg( t, "Got scrape response for '%s': %s (%d)", (t ? t->name : "(null)"), (req ? req->response_code_line : "(no line)"), (req ? req->response_code : -1) );
tr_free( vhash ); tr_free( vhash );
if( t == NULL ) /* tracker's been closed... */ if( t == NULL ) /* tracker's been closed... */
@ -824,6 +827,7 @@ connectionClosedCB( struct evhttp_connection * evcon, void * vhandle )
--handle->tracker->socketCount; --handle->tracker->socketCount;
dbgmsg( NULL, "decrementing socket count to %d", handle->tracker->socketCount ); dbgmsg( NULL, "decrementing socket count to %d", handle->tracker->socketCount );
pulse( handle );
} }
static struct evhttp_connection* static struct evhttp_connection*
@ -834,44 +838,26 @@ getConnection( tr_handle * handle, const char * address, int port )
return c; return c;
} }
static int static void
invokeRequest( tr_handle * handle, const struct tr_tracker_request * req ) invokeRequest( tr_handle * handle, const struct tr_tracker_request * req )
{ {
int err;
struct evhttp_connection * evcon = getConnection( handle, req->address, req->port ); struct evhttp_connection * evcon = getConnection( handle, req->address, req->port );
dbgmsg( NULL, "sending '%s' to tracker %s:%d, timeout is %d", req->uri, req->address, req->port, (int)req->timeout ); tr_tracker * t = findTracker( handle, req->torrent_hash );
dbgmsg( t, "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_connection_set_timeout( evcon, req->timeout );
err = evhttp_make_request( evcon, req->req, EVHTTP_REQ_GET, req->uri ); if( evhttp_make_request( evcon, req->req, EVHTTP_REQ_GET, req->uri ))
if( !err ) { publishErrorMessageAndStop( t, "Tracker could not be reached." );
else {
++handle->tracker->socketCount; ++handle->tracker->socketCount;
dbgmsg( NULL, "incremented socket count to %d", handle->tracker->socketCount ); dbgmsg( t, "incremented socket count to %d", handle->tracker->socketCount );
} }
return err;
} }
static void static void
invokeNextInQueue( tr_handle * handle, tr_list ** list ) invokeNextInQueue( tr_handle * handle, tr_list ** list )
{ {
struct tr_tracker_request * req = tr_list_pop_front( list ); struct tr_tracker_request * req = tr_list_pop_front( list );
const int err = invokeRequest( handle, req ); 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 ); freeRequest( req );
} }
@ -901,18 +887,6 @@ enqueueRequest( tr_handle * handle, const tr_tracker * tracker, int reqtype )
tr_list_append( &handle->tracker->requestQueue, req ); 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 static int
pulse( void * vhandle ) pulse( void * vhandle )
{ {
@ -929,11 +903,6 @@ pulse( void * vhandle )
{ {
tr_tracker * t = tor->tracker; tr_tracker * t = tor->tracker;
if( t->resendRequestAt && ( now >= t->resendRequestAt ) ) {
t->resendRequestAt = 0;
maybeRequeueRequest( handle, t, t->resendRequestType );
}
if( t->scrapeAt && trackerSupportsScrape( t ) && ( now >= t->scrapeAt ) ) { if( t->scrapeAt && trackerSupportsScrape( t ) && ( now >= t->scrapeAt ) ) {
t->scrapeAt = 0; t->scrapeAt = 0;
enqueueScrape( handle, t ); enqueueScrape( handle, t );