#include <sys/stat.h>
#include <unistd.h> /* unlink, stat */
+#include <event.h> /* struct evbuffer */
+
#include "transmission.h"
#include "bencode.h"
#include "crypto.h" /* tr_sha1 */
void tr_metainfoFree( tr_info * inf )
{
tr_file_index_t ff;
- int i, j;
+ int i;
for( ff=0; ff<inf->fileCount; ++ff )
tr_free( inf->files[ff].name );
tr_free( inf->creator );
tr_free( inf->torrent );
tr_free( inf->name );
- tr_free( inf->primaryAddress );
- for( i=0; i<inf->trackerTiers; ++i ) {
- for( j=0; j<inf->trackerList[i].count; ++j )
- tr_trackerInfoClear( &inf->trackerList[i].list[j] );
- tr_free( inf->trackerList[i].list );
+ for( i=0; i<inf->trackerCount; ++i ) {
+ tr_free( inf->trackers[i].announce );
+ tr_free( inf->trackers[i].scrape );
}
- tr_free( inf->trackerList );
+ tr_free( inf->trackers );
memset( inf, '\0', sizeof(tr_info) );
}
static int getannounce( tr_info * inf, tr_benc * meta )
{
- tr_benc * val, * urlval;
- char * address, * announce;
- int ii, jj, port, random;
- tr_tracker_info * sublist;
- void * swapping;
+ const char * str;
+ tr_tracker_info * trackers = NULL;
+ int trackerCount = 0;
+ tr_benc * tiers;
/* Announce-list */
- val = tr_bencDictFind( meta, "announce-list" );
- if( tr_bencIsList(val) && 0 < val->val.l.count )
+ if( tr_bencDictFindList( meta, "announce-list", &tiers ) )
{
- inf->trackerTiers = 0;
- inf->trackerList = calloc( val->val.l.count,
- sizeof( inf->trackerList[0] ) );
-
- /* iterate through the announce-list's tiers */
- for( ii = 0; ii < val->val.l.count; ii++ )
- {
- int subcount = 0;
- tr_benc * subval = &val->val.l.vals[ii];
-
- if( !tr_bencIsList(subval) || 0 >= subval->val.l.count )
- continue;
-
- sublist = calloc( subval->val.l.count, sizeof( sublist[0] ) );
-
- /* iterate through the tier's items */
- for( jj = 0; jj < subval->val.l.count; jj++ )
- {
- tr_tracker_info tmp;
-
- urlval = &subval->val.l.vals[jj];
- if( TYPE_STR != urlval->type ||
- tr_trackerInfoInit( &tmp, urlval->val.s.s, urlval->val.s.i ) )
- {
- continue;
- }
-
- if( !inf->primaryAddress ) {
- char buf[1024];
- snprintf( buf, sizeof(buf), "%s:%d", tmp.address, tmp.port );
- inf->primaryAddress = tr_strdup( buf );
+ int n;
+ int i, j;
+
+ n = 0;
+ for( i=0; i<tiers->val.l.count; ++i )
+ n += tiers->val.l.vals[i].val.l.count;
+
+ trackers = tr_new0( tr_tracker_info, n );
+ trackerCount = 0;
+
+ for( i=0; i<tiers->val.l.count; ++i ) {
+ const tr_benc * tier = &tiers->val.l.vals[i];
+ for( j=0; tr_bencIsList(tier) && j<tier->val.l.count; ++j ) {
+ const tr_benc * address = &tier->val.l.vals[j];
+ if( tr_bencIsString( address ) && tr_httpIsValidURL( address->val.s.s ) ) {
+ trackers[trackerCount].tier = i;
+ trackers[trackerCount].announce = tr_strndup( address->val.s.s, address->val.s.i );
+ trackers[trackerCount++].scrape = announceToScrape( address->val.s.s );
+ /*fprintf( stderr, "tier %d: %s\n", i, address->val.s.s );*/
}
-
- /* place the item info in a random location in the sublist */
- random = tr_rand( subcount + 1 );
- if( random != subcount )
- sublist[subcount] = sublist[random];
- sublist[random] = tmp;
- subcount++;
- }
-
- /* just use sublist as-is if it's full */
- if( subcount == subval->val.l.count )
- {
- inf->trackerList[inf->trackerTiers].list = sublist;
- inf->trackerList[inf->trackerTiers].count = subcount;
- inf->trackerTiers++;
- }
- /* if we skipped some of the tier's items then trim the sublist */
- else if( 0 < subcount )
- {
- inf->trackerList[inf->trackerTiers].list = calloc( subcount, sizeof( sublist[0] ) );
- memcpy( inf->trackerList[inf->trackerTiers].list, sublist,
- sizeof( sublist[0] ) * subcount );
- inf->trackerList[inf->trackerTiers].count = subcount;
- inf->trackerTiers++;
- free( sublist );
- }
- /* drop the whole sublist if we didn't use any items at all */
- else
- {
- free( sublist );
}
}
/* did we use any of the tiers? */
- if( 0 == inf->trackerTiers )
- {
+ if( !trackerCount ) {
tr_inf( _( "Invalid metadata entry \"%s\"" ), "announce-list" );
- free( inf->trackerList );
- inf->trackerList = NULL;
- }
- /* trim unused sublist pointers */
- else if( inf->trackerTiers < val->val.l.count )
- {
- swapping = inf->trackerList;
- inf->trackerList = calloc( inf->trackerTiers,
- sizeof( inf->trackerList[0] ) );
- memcpy( inf->trackerList, swapping,
- sizeof( inf->trackerList[0] ) * inf->trackerTiers );
- free( swapping );
+ tr_free( trackers );
+ trackers = NULL;
}
}
/* Regular announce value */
- val = tr_bencDictFind( meta, "announce" );
- if( !tr_bencIsString( val ) )
+ if( !trackerCount
+ && tr_bencDictFindStr( meta, "announce", &str )
+ && tr_httpIsValidURL( str ) )
{
- tr_err( _( "Missing metadata entry \"%s\"" ), "announce" );
- return TR_EINVALID;
- }
-
- if( !inf->trackerTiers )
- {
- char buf[4096], *pch;
- strlcpy( buf, val->val.s.s, sizeof( buf ) );
- pch = buf;
- while( isspace( *pch ) )
- ++pch;
-
- if( tr_httpParseURL( pch, -1, &address, &port, &announce ) )
- {
- tr_err( _( "Invalid announce URL \"%s\"" ), val->val.s.s );
- return TR_EINVALID;
- }
- sublist = calloc( 1, sizeof( sublist[0] ) );
- sublist[0].address = address;
- sublist[0].port = port;
- sublist[0].announce = announce;
- sublist[0].scrape = announceToScrape( announce );
- inf->trackerList = calloc( 1, sizeof( inf->trackerList[0] ) );
- inf->trackerList[0].list = sublist;
- inf->trackerList[0].count = 1;
- inf->trackerTiers = 1;
-
- if( !inf->primaryAddress ) {
- char buf[1024];
- snprintf( buf, sizeof(buf), "%s:%d", sublist[0].address, sublist[0].port );
- inf->primaryAddress = tr_strdup( buf );
- }
-
+ trackers = tr_new0( tr_tracker_info, 1 );
+ trackers[trackerCount].tier = 0;
+ trackers[trackerCount].announce = tr_strdup( str );
+ trackers[trackerCount++].scrape = announceToScrape( str );
+ /*fprintf( stderr, "single announce: [%s]\n", str );*/
}
+ inf->trackers = trackers;
+ inf->trackerCount = trackerCount;
return TR_OK;
}
-static char * announceToScrape( const char * announce )
+static char *
+announceToScrape( const char * announce )
{
- char old[] = "announce";
- int oldlen = 8;
- char new[] = "scrape";
- int newlen = 6;
- char * slash, * scrape;
- size_t scrapelen, used;
-
+ char * scrape = NULL;
+ const char * slash;
+ struct evbuffer * buf;
+
+ /* To derive the scrape URL use the following steps:
+ * Begin with the announce URL. Find the last '/' in it.
+ * If the text immediately following that '/' isn't 'announce'
+ * it will be taken as a sign that that tracker doesn't support
+ * the scrape convention. If it does, substitute 'scrape' for
+ * 'announce' to find the scrape page. */
+
+ /* is the last slash followed by "announce"? */
slash = strrchr( announce, '/' );
- if( NULL == slash )
- {
+ if( !slash )
return NULL;
- }
- slash++;
-
- if( 0 != strncmp( slash, old, oldlen ) )
- {
+ ++slash;
+ if( strncmp( slash, "announce", 8 ) )
return NULL;
- }
- scrapelen = strlen( announce ) - oldlen + newlen;
- scrape = calloc( scrapelen + 1, 1 );
- if( NULL == scrape )
- {
- return NULL;
- }
- assert( ( size_t )( slash - announce ) < scrapelen );
- memcpy( scrape, announce, slash - announce );
- used = slash - announce;
- strncat( scrape, new, scrapelen - used );
- used += newlen;
- assert( strlen( scrape ) == used );
- if( used < scrapelen )
- {
- assert( strlen( slash + oldlen ) == scrapelen - used );
- strncat( scrape, slash + oldlen, scrapelen - used );
- }
+ /* build the scrape url */
+ buf = evbuffer_new( );
+ evbuffer_add( buf, announce, slash-announce );
+ evbuffer_add( buf, "scrape", 6 );
+ evbuffer_add_printf( buf, "%s", slash+8 );
+ scrape = tr_strdup( ( char * ) EVBUFFER_DATA( buf ) );
+ evbuffer_free( buf );
return scrape;
}
-int
-tr_trackerInfoInit( tr_tracker_info * info,
- const char * address,
- int address_len )
-{
- int ret = tr_httpParseURL( address, address_len,
- &info->address,
- &info->port,
- &info->announce );
- if( !ret )
- info->scrape = announceToScrape( info->announce );
-
- return ret;
-}
-
-void
-tr_trackerInfoClear( tr_tracker_info * info )
-{
- tr_free( info->address );
- tr_free( info->announce );
- tr_free( info->scrape );
- memset( info, '\0', sizeof(tr_tracker_info) );
-}
-
void
tr_metainfoRemoveSaved( const tr_handle * handle,
const tr_info * inf )
#include <libgen.h> /* basename */
#include <event.h>
-#include <evhttp.h>
#include "transmission.h"
#include "bencode.h"
#include "completion.h"
-#include "list.h"
#include "net.h"
#include "port-forwarding.h"
#include "publish.h"
#include "trcompat.h" /* strlcpy */
#include "trevent.h"
#include "utils.h"
+#include "web.h"
enum
{
+ HTTP_OK = 200,
+
/* seconds between tracker pulses */
PULSE_INTERVAL_MSEC = 1000,
STOP_TIMEOUT_INTERVAL_SEC = 5,
/* the value of the 'numwant' argument passed in tracker requests. */
- NUMWANT = 200,
+ NUMWANT = 150,
/* the length of the 'key' argument passed in tracker requests */
KEYLEN = 10
struct tr_tracker
{
- tr_handle * handle;
+ unsigned int isRunning : 1;
+
+ uint8_t randOffset;
+
+ tr_session * session;
/* these are set from the latest scrape or tracker response */
int announceIntervalSec;
int scrapeIntervalSec;
int retryScrapeIntervalSec;
- tr_tracker_info * redirect;
- tr_tracker_info * addresses;
- int addressIndex;
- int addressCount;
- int * tierFronts;
+ /* index into the torrent's tr_info.trackers array */
+ int trackerIndex;
/* sent as the "key" argument in tracker requests
to verify us if our IP address changes.
/* torrent hash string */
uint8_t hash[SHA_DIGEST_LENGTH];
- char escaped[SHA_DIGEST_LENGTH * 3 + 1];
+ char escaped[SHA_DIGEST_LENGTH*3 + 1];
char * name;
/* corresponds to the peer_id sent as a tracker request parameter.
time_t scrapeAt;
time_t lastScrapeTime;
- char lastScrapeResponse[512];
+ long lastScrapeResponse;
time_t lastAnnounceTime;
- char lastAnnounceResponse[512];
-
- int randOffset;
-
- unsigned int isRunning : 1;
+ long lastAnnounceResponse;
};
/**
char * myfile = tr_strdup( file );
evbuffer_add_printf( buf, "[%s] ", tr_getLogTimeStr( timestr, sizeof(timestr) ) );
- if( t != NULL )
+ if( t )
evbuffer_add_printf( buf, "%s ", t->name );
va_start( args, fmt );
evbuffer_add_vprintf( buf, fmt, args );
****
***/
+static const tr_tracker_info *
+getCurrentAddressFromTorrent( const tr_tracker * t, const tr_torrent * tor )
+{
+ assert( t->trackerIndex >= 0 );
+ assert( t->trackerIndex < tor->info.trackerCount );
+ return tor->info.trackers + t->trackerIndex;
+}
+
static const tr_tracker_info *
getCurrentAddress( const tr_tracker * t )
{
- assert( t->addresses != NULL );
- assert( t->addressIndex >= 0 );
- assert( t->addressIndex < t->addressCount );
-
- return t->redirect ? t->redirect
- : t->addresses + t->addressIndex;
+ const tr_torrent * torrent;
+ if(( torrent = tr_torrentFindFromHash( t->session, t->hash )))
+ return getCurrentAddressFromTorrent( t, torrent );
+ return NULL;
}
static int
-trackerSupportsScrape( const tr_tracker * t )
+trackerSupportsScrape( const tr_tracker * t, const tr_torrent * tor )
{
- const tr_tracker_info * info = getCurrentAddress( t );
-
- return ( info != NULL )
- && ( info->scrape != NULL )
- && ( info->scrape[0] != '\0' );
+ const tr_tracker_info * info = getCurrentAddressFromTorrent( t, tor );
+ return info && info->scrape;
}
/***
****
***/
-struct torrent_hash
-{
- tr_handle * handle;
- uint8_t hash[SHA_DIGEST_LENGTH];
-};
-
-static struct torrent_hash*
-torrentHashNew( tr_handle * handle, const tr_tracker * t )
-{
- struct torrent_hash * data = tr_new( struct torrent_hash, 1 );
- data->handle = handle;
- memcpy( data->hash, t->hash, SHA_DIGEST_LENGTH );
- return data;
-}
-
tr_tracker *
-findTrackerFromHash( struct torrent_hash * data )
+findTracker( tr_session * session, const uint8_t * hash )
{
- tr_torrent * torrent = tr_torrentFindFromHash( data->handle, data->hash );
- return torrent ? torrent->tracker : NULL;
-}
-
-tr_tracker *
-findTracker( tr_handle * handle, const uint8_t * hash )
-{
- tr_torrent * torrent = tr_torrentFindFromHash( handle, hash );
+ tr_torrent * torrent = tr_torrentFindFromHash( session, hash );
return torrent ? torrent->tracker : NULL;
}
static void
publishMessage( tr_tracker * t, const char * msg, int type )
{
- if( t != NULL )
+ if( t )
{
tr_tracker_event event = emptyEvent;
event.hash = t->hash;
}
static void
-publishNewPeers( tr_tracker * t, int allAreSeeds, void * compact, int compactLen )
+publishNewPeers( tr_tracker * t, int allAreSeeds,
+ void * compact, int compactLen )
{
tr_tracker_event event = emptyEvent;
event.hash = t->hash;
****
***/
-static void onReqDone( tr_handle * handle );
-
-static void
-onStoppedResponse( struct evhttp_request * req UNUSED, void * handle )
-{
- dbgmsg( NULL, "got a response to some `stop' message" );
- onReqDone( handle );
-}
-
-static int
-parseBencResponse( struct evhttp_request * req, tr_benc * setme )
-{
- const unsigned char * body = EVBUFFER_DATA( req->input_buffer );
- const int bodylen = EVBUFFER_LENGTH( req->input_buffer );
- return tr_bencLoad( body, bodylen, setme, NULL );
-}
+static void onReqDone( tr_session * session );
static void
-updateAddresses( tr_tracker * t, const struct evhttp_request * req, int * tryAgain )
+updateAddresses( tr_tracker * t, long response_code, int * tryAgain )
{
int moveToNextAddress = FALSE;
+ tr_torrent * torrent = tr_torrentFindFromHash( t->session, t->hash );
- if( !req ) /* tracker didn't respond */
+ if( !response_code ) /* tracker didn't respond */
{
tr_ninf( t->name, _( "Tracker hasn't responded yet. Retrying..." ) );
moveToNextAddress = TRUE;
}
- else if( req->response_code == HTTP_OK )
+ else if( response_code == HTTP_OK )
{
- if( t->redirect != NULL )
- {
- /* multitracker spec: "if a connection with a tracker is
- successful, it will be moved to the front of the tier." */
- const int i = t->addressIndex;
- const int j = t->tierFronts[i];
- const tr_tracker_info swap = t->addresses[i];
- t->addresses[i] = t->addresses[j];
- t->addresses[j] = swap;
- }
- }
- else if( ( req->response_code == HTTP_MOVEPERM )
- || ( req->response_code == HTTP_MOVETEMP ) )
- {
- const char * loc = evhttp_find_header( req->input_headers, "Location" );
- tr_tracker_info tmp;
- if( tr_trackerInfoInit( &tmp, loc, -1 ) ) /* a bad redirect? */
- {
- moveToNextAddress = TRUE;
- }
- else if( req->response_code == HTTP_MOVEPERM )
- {
- tr_tracker_info * cur = &t->addresses[t->addressIndex];
- tr_trackerInfoClear( cur );
- *cur = tmp;
- }
- else if( req->response_code == HTTP_MOVETEMP )
- {
- if( t->redirect == NULL )
- t->redirect = tr_new0( tr_tracker_info, 1 );
- else
- tr_trackerInfoClear( t->redirect );
- *t->redirect = tmp;
- }
+#if 0
+/* FIXME */
+ /* multitracker spec: "if a connection with a tracker is
+ successful, it will be moved to the front of the tier." */
+ const int i = t->addressIndex;
+ const int j = t->tierFronts[i];
+ const tr_tracker_info swap = t->addresses[i];
+ t->addresses[i] = t->addresses[j];
+ t->addresses[j] = swap;
+#endif
}
else
{
if( moveToNextAddress )
{
- if ( ++t->addressIndex >= t->addressCount ) /* we've tried them all */
+ if ( ++t->trackerIndex >= torrent->info.trackerCount ) /* we've tried them all */
{
*tryAgain = FALSE;
- t->addressIndex = 0;
+ t->trackerIndex = 0;
}
else
{
- const tr_tracker_info * n = getCurrentAddress( t );
- tr_ninf( t->name, _( "Trying next tracker \"%s:%d\"" ), n->address, n->port );
+ const tr_tracker_info * n = getCurrentAddressFromTorrent( t, torrent );
+ tr_ninf( t->name, _( "Trying tracker \"%s\"" ), n->announce );
}
}
}
for( i=0, walk=compact; i<peerCount; ++i )
{
+ const char * s;
+ int64_t itmp;
struct in_addr addr;
tr_port_t port;
- tr_benc * val;
tr_benc * peer = &bePeers->val.l.vals[i];
- val = tr_bencDictFind( peer, "ip" );
- if( !val || val->type!=TYPE_STR || tr_netResolve(val->val.s.s, &addr) )
+ if( !tr_bencDictFindStr( peer, "ip", &s ) || tr_netResolve( s, &addr ) )
continue;
memcpy( walk, &addr, 4 );
walk += 4;
- val = tr_bencDictFind( peer, "port" );
- if( !val || val->type!=TYPE_INT || val->val.i<0 || val->val.i>0xffff )
+ if( !tr_bencDictFindInt( peer, "port", &itmp ) || itmp<0 || itmp>0xffff )
continue;
- port = htons( val->val.i );
+ port = htons( itmp );
memcpy( walk, &port, 2 );
walk += 2;
}
}
static void
-onTrackerResponse( struct evhttp_request * req, void * vhash )
+onStoppedResponse( tr_session * session,
+ long responseCode UNUSED,
+ const void * response UNUSED,
+ size_t responseLen UNUSED,
+ void * torrent_hash UNUSED )
+{
+ dbgmsg( NULL, "got a response to some `stop' message" );
+ onReqDone( session );
+}
+
+static void
+onTrackerResponse( tr_session * session,
+ long responseCode,
+ const void * response,
+ size_t responseLen,
+ void * torrent_hash )
{
int tryAgain;
- int responseCode;
- struct torrent_hash * torrent_hash = (struct torrent_hash*) vhash;
- tr_tracker * t = findTrackerFromHash( torrent_hash );
+ tr_tracker * t;
- onReqDone( torrent_hash->handle );
+ onReqDone( session );
+ t = findTracker( session, torrent_hash );
tr_free( torrent_hash );
-
- if( t == NULL ) /* tracker has been closed */
+ if( !t ) /* tracker's been closed */
return;
- dbgmsg( t, "got response from tracker: \"%s\"",
- ( req && req->response_code_line ) ? req->response_code_line
- : "(null)" );
+ dbgmsg( t, "tracker response: %d", responseCode );
+ tr_ndbg( t->name, "tracker response: %d", responseCode );
+ t->lastAnnounceResponse = responseCode;
- *t->lastAnnounceResponse = '\0';
- if( req && req->response_code_line )
- strlcpy( t->lastAnnounceResponse, req->response_code_line, sizeof( t->lastAnnounceResponse ) );
-
- tr_ndbg( t->name, "tracker response: %s",
- ( req ? req->response_code_line : "(null)") );
-
- if( req && ( req->response_code == HTTP_OK ) )
+ if( responseCode == HTTP_OK )
{
tr_benc benc;
- const int bencLoaded = !parseBencResponse( req, &benc );
-
+ const int bencLoaded = !tr_bencLoad( response, responseLen, &benc, 0 );
publishErrorClear( t );
-
- if( bencLoaded && benc.type==TYPE_DICT )
+ if( bencLoaded && tr_bencIsDict( &benc ) )
{
tr_benc * tmp;
+ int64_t i;
int incomplete = -1;
+ const char * str;
- if(( tmp = tr_bencDictFind( &benc, "failure reason" ))) {
- dbgmsg( t, "got failure message [%s]", tmp->val.s.s );
- publishErrorMessageAndStop( t, tmp->val.s.s );
- }
+ if(( tr_bencDictFindStr( &benc, "failure reason", &str )))
+ publishErrorMessageAndStop( t, str );
- if(( tmp = tr_bencDictFind( &benc, "warning message" ))) {
- dbgmsg( t, "got warning message [%s]", tmp->val.s.s );
- publishWarning( t, tmp->val.s.s );
- }
+ if(( tr_bencDictFindStr( &benc, "warning message", &str )))
+ publishWarning( t, str );
- if(( tmp = tr_bencDictFind( &benc, "interval" ))) {
- dbgmsg( t, "setting interval to %d", tmp->val.i );
- t->announceIntervalSec = tmp->val.i;
+ if(( tr_bencDictFindInt( &benc, "interval", &i ))) {
+ dbgmsg( t, "setting interval to %d", (int)i );
+ t->announceIntervalSec = i;
}
- if(( tmp = tr_bencDictFind( &benc, "min interval" ))) {
- dbgmsg( t, "setting min interval to %d", tmp->val.i );
- t->announceMinIntervalSec = tmp->val.i;
+ if(( tr_bencDictFindInt( &benc, "min interval", &i ))) {
+ dbgmsg( t, "setting min interval to %d", (int)i );
+ t->announceMinIntervalSec = i;
}
- if(( tmp = tr_bencDictFind( &benc, "tracker id" )))
- t->trackerID = tr_strndup( tmp->val.s.s, tmp->val.s.i );
+ if(( tr_bencDictFindStr( &benc, "tracker id", &str )))
+ t->trackerID = tr_strdup( str );
- if(( tmp = tr_bencDictFind( &benc, "complete" )))
- t->seederCount = tmp->val.i;
+ if(( tr_bencDictFindInt( &benc, "complete", &i )))
+ t->seederCount = i;
- if(( tmp = tr_bencDictFind( &benc, "incomplete" )))
- t->leecherCount = incomplete = tmp->val.i;
+ if(( tr_bencDictFindInt( &benc, "incomplete", &i )))
+ t->leecherCount = incomplete = i;
if(( tmp = tr_bencDictFind( &benc, "peers" )))
{
tr_bencFree( &benc );
}
- updateAddresses( t, req, &tryAgain );
+ updateAddresses( t, responseCode, &tryAgain );
/**
***
if( tryAgain )
responseCode = 300;
- else if( req )
- responseCode = req->response_code;
- else
- responseCode = 503;
if( 200<=responseCode && responseCode<=299 )
{
- dbgmsg( t, "request succeeded. reannouncing in %d seconds",
- t->announceIntervalSec );
- t->reannounceAt = time( NULL ) + t->randOffset + t->announceIntervalSec;
+ const int interval = t->announceIntervalSec + t->randOffset;
+ dbgmsg( t, "request succeeded. reannouncing in %d seconds", interval );
+ t->reannounceAt = time( NULL ) + interval;
t->manualAnnounceAllowedAt = time( NULL ) + t->announceMinIntervalSec;
}
else if( 300<=responseCode && responseCode<=399 )
{
- const int interval = 5;
- dbgmsg( t, "got a redirect. retrying in %d seconds", interval );
-
/* it's a redirect... updateAddresses() has already
* parsed the redirect, all that's left is to retry */
+ const int interval = 5;
+ dbgmsg( t, "got a redirect. retrying in %d seconds", interval );
t->reannounceAt = time( NULL ) + interval;
t->manualAnnounceAllowedAt = time( NULL ) + t->announceMinIntervalSec;
}
else if( 400<=responseCode && responseCode<=499 )
{
- 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
* malformed syntax. The client SHOULD NOT repeat the
* request without modifications. */
- publishErrorMessageAndStop( t, err );
+ publishErrorMessageAndStop( t, _( "Tracker returned a 4xx message" ) );
t->manualAnnounceAllowedAt = ~(time_t)0;
t->reannounceAt = 0;
}
else if( 500<=responseCode && responseCode<=599 )
{
- dbgmsg( t, "Got a 5xx error... retrying in one minute." );
-
/* 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. */
- if( req && req->response_code_line )
- publishWarning( t, req->response_code_line );
t->manualAnnounceAllowedAt = ~(time_t)0;
t->reannounceAt = time( NULL ) + 60;
}
else
{
- dbgmsg( t, "Invalid response from tracker... retrying in two minutes." );
-
/* WTF did we get?? */
- if( req && req->response_code_line )
- publishWarning( t, req->response_code_line );
+ dbgmsg( t, "Invalid response from tracker... retrying in two minutes." );
t->manualAnnounceAllowedAt = ~(time_t)0;
t->reannounceAt = time( NULL ) + t->randOffset + 120;
}
}
static void
-onScrapeResponse( struct evhttp_request * req, void * vhash )
+onScrapeResponse( tr_session * session,
+ long responseCode,
+ const void * response,
+ size_t responseLen,
+ void * torrent_hash )
{
int tryAgain;
- int responseCode;
- struct torrent_hash * torrent_hash = (struct torrent_hash*) vhash;
- tr_tracker * t = findTrackerFromHash( torrent_hash );
+ tr_tracker * t;
- onReqDone( torrent_hash->handle );
+ onReqDone( session );
+ t = findTracker( session, torrent_hash );
tr_free( torrent_hash );
-
- 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) );
-
- if( t == NULL ) /* tracker's been closed... */
+ if( !t ) /* tracker's been closed... */
return;
- *t->lastScrapeResponse = '\0';
- if( req && req->response_code_line )
- strlcpy( t->lastScrapeResponse, req->response_code_line, sizeof( t->lastScrapeResponse ) );
-
- tr_ndbg( t->name, "Got scrape response: \"%s\"",
- ( ( req && req->response_code_line ) ? req->response_code_line : "(null)") );
+ dbgmsg( t, "scrape response: %ld\n", responseCode );
+ tr_ndbg( t->name, "scrape response: %d", responseCode );
+ t->lastScrapeResponse = responseCode;
- if( req && ( req->response_code == HTTP_OK ) )
+ if( responseCode == HTTP_OK )
{
tr_benc benc, *files;
- const int bencLoaded = !parseBencResponse( req, &benc );
-
- if( bencLoaded
- && (( files = tr_bencDictFind( &benc, "files" ) ))
- && ( files->type == TYPE_DICT ) )
+ const int bencLoaded = !tr_bencLoad( response, responseLen, &benc, 0 );
+ if( bencLoaded && tr_bencDictFindDict( &benc, "files", &files ) )
{
int i;
for( i=0; i<files->val.l.count; i+=2 )
{
+ int64_t itmp;
const uint8_t* hash =
- (const uint8_t*) files->val.l.vals[i].val.s.s;
- tr_benc *tmp, *flags;
- tr_benc *tordict = &files->val.l.vals[i+1];
+ (const uint8_t*) files->val.l.vals[i].val.s.s;
+ tr_benc * flags;
+ tr_benc * tordict = &files->val.l.vals[i+1];
if( memcmp( t->hash, hash, SHA_DIGEST_LENGTH ) )
continue;
publishErrorClear( t );
- if(( tmp = tr_bencDictFind( tordict, "complete" )))
- t->seederCount = tmp->val.i;
+ if(( tr_bencDictFindInt( tordict, "complete", &itmp )))
+ t->seederCount = itmp;
- if(( tmp = tr_bencDictFind( tordict, "incomplete" )))
- t->leecherCount = tmp->val.i;
+ if(( tr_bencDictFindInt( tordict, "incomplete", &itmp )))
+ t->leecherCount = itmp;
- if(( tmp = tr_bencDictFind( tordict, "downloaded" )))
- t->timesDownloaded = tmp->val.i;
+ if(( tr_bencDictFindInt( tordict, "downloaded", &itmp )))
+ t->timesDownloaded = itmp;
- if(( flags = tr_bencDictFind( tordict, "flags" )))
- if(( tmp = tr_bencDictFind( flags, "min_request_interval")))
- t->scrapeIntervalSec = tmp->val.i;
+ if( tr_bencDictFindDict( tordict, "flags", &flags ))
+ if(( tr_bencDictFindInt( flags, "min_request_interval", &itmp )))
+ t->scrapeIntervalSec = i;
tr_ndbg( t->name, "Scrape successful. Rescraping in %d seconds.",
t->scrapeIntervalSec );
tr_bencFree( &benc );
}
- updateAddresses( t, req, &tryAgain );
+ updateAddresses( t, responseCode, &tryAgain );
/**
***
if( tryAgain )
responseCode = 300;
- else if( req )
- responseCode = req->response_code;
- else
- responseCode = 503;
if( 200<=responseCode && responseCode<=299 )
{
else
{
const int interval = t->retryScrapeIntervalSec + t->randOffset;
- dbgmsg( t, "Tracker responded to scrape with %d. Retrying in %d seconds.", responseCode, interval );
+ dbgmsg( t, "Tracker responded to scrape with %d. Retrying in %d seconds.",
+ responseCode, interval );
t->retryScrapeIntervalSec *= 2;
t->scrapeAt = time( NULL ) + interval;
}
struct tr_tracker_request
{
- int port;
- int timeout;
+ char * url;
int reqtype; /* TR_REQ_* */
- char * address;
- char * uri;
- struct evhttp_request * req;
uint8_t torrent_hash[SHA_DIGEST_LENGTH];
+ tr_web_done_func * done_func;
+ tr_session * session;
};
static void
freeRequest( struct tr_tracker_request * req )
{
- tr_free( req->address );
- tr_free( req->uri );
+ tr_free( req->url );
tr_free( req );
}
static void
-addCommonHeaders( const tr_tracker * t,
- struct evhttp_request * req )
-{
- char buf[1024];
- const tr_tracker_info * address = getCurrentAddress( t );
- snprintf( buf, sizeof(buf), "%s:%d", address->address, address->port );
- evhttp_add_header( req->output_headers, "Host", buf );
- evhttp_add_header( req->output_headers, "Connection", "close" );
- evhttp_add_header( req->output_headers, "User-Agent",
- TR_NAME "/" LONG_VERSION_STRING );
-}
-
-static char*
buildTrackerRequestURI( const tr_tracker * t,
const tr_torrent * torrent,
- const char * eventName )
+ const char * eventName,
+ struct evbuffer * buf )
{
const int isStopping = !strcmp( eventName, "stopped" );
const int numwant = isStopping ? 0 : NUMWANT;
- struct evbuffer * buf = evbuffer_new( );
- char * ret;
-
- const char * ann = getCurrentAddress(t)->announce;
+ const char * ann = getCurrentAddressFromTorrent(t,torrent)->announce;
- evbuffer_add_printf( buf, "%s"
- "%cinfo_hash=%s"
+ evbuffer_add_printf( buf, "%cinfo_hash=%s"
"&peer_id=%s"
"&port=%d"
"&uploaded=%"PRIu64
"&compact=1"
"&numwant=%d"
"&key=%s"
- "&supportcrypto=1"
- "&requirecrypto=%d"
"%s%s"
"%s%s",
- ann,
strchr(ann, '?') ? '&' : '?',
t->escaped,
t->peer_id,
- tr_sharedGetPublicPort( t->handle->shared ),
+ tr_sharedGetPublicPort( t->session->shared ),
torrent->uploadedCur,
torrent->downloadedCur,
torrent->corruptCur,
tr_cpLeftUntilComplete( torrent->completion ),
numwant,
t->key_param,
- ( t->handle->encryptionMode==TR_ENCRYPTION_REQUIRED ? 1 : 0 ),
( ( eventName && *eventName ) ? "&event=" : "" ),
( ( eventName && *eventName ) ? eventName : "" ),
( ( t->trackerID && *t->trackerID ) ? "&trackerid=" : "" ),
( ( t->trackerID && *t->trackerID ) ? t->trackerID : "" ) );
-
- ret = tr_strdup( (char*) EVBUFFER_DATA( buf ) );
- evbuffer_free( buf );
- return ret;
}
static struct tr_tracker_request*
-createRequest( tr_handle * handle, const tr_tracker * tracker, int reqtype )
+createRequest( tr_session * session, const tr_tracker * tracker, int reqtype )
{
- 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 );
+ static const char* strings[] = { "started", "completed", "stopped", "", "err" };
+ const tr_torrent * torrent = tr_torrentFindFromHash( session, tracker->hash );
+ const tr_tracker_info * address = getCurrentAddressFromTorrent( tracker, torrent );
const int isStopping = reqtype == TR_REQ_STOPPED;
- const char * eventName = strings[reqtype];
struct tr_tracker_request * req;
+ struct evbuffer * url;
+
+ url = evbuffer_new( );
+ evbuffer_add_printf( url, "%s", address->announce );
+ buildTrackerRequestURI( tracker, torrent, strings[reqtype], url );
req = tr_new0( struct tr_tracker_request, 1 );
- req->address = tr_strdup( address->address );
- req->port = address->port;
- req->uri = buildTrackerRequestURI( tracker, torrent, eventName );
- req->timeout = isStopping ? STOP_TIMEOUT_INTERVAL_SEC : TIMEOUT_INTERVAL_SEC;
+ req->session = session;
req->reqtype = reqtype;
- req->req = isStopping
- ? evhttp_request_new( onStoppedResponse, handle )
- : evhttp_request_new( onTrackerResponse, torrentHashNew(handle, tracker) );
+ req->done_func = isStopping ? onStoppedResponse : onTrackerResponse;
+ req->url = tr_strdup( ( char * ) EVBUFFER_DATA( url ) );
memcpy( req->torrent_hash, tracker->hash, SHA_DIGEST_LENGTH );
- addCommonHeaders( tracker, req->req );
+ evbuffer_free( url );
return req;
}
static struct tr_tracker_request*
-createScrape( tr_handle * handle, const tr_tracker * tracker )
+createScrape( tr_session * session, const tr_tracker * tracker )
{
const tr_tracker_info * a = getCurrentAddress( tracker );
struct tr_tracker_request * req;
+ struct evbuffer * url = evbuffer_new( );
+
+ evbuffer_add_printf( url, "%s%cinfo_hash=%s",
+ a->scrape, strchr(a->scrape,'?')?'&':'?',
+ tracker->escaped );
req = tr_new0( struct tr_tracker_request, 1 );
- req->address = tr_strdup( a->address );
- req->port = a->port;
- req->timeout = TIMEOUT_INTERVAL_SEC;
- req->req = evhttp_request_new( onScrapeResponse, torrentHashNew( handle, tracker ) );
+ req->session = session;
req->reqtype = TR_REQ_SCRAPE;
- tr_asprintf( &req->uri, "%s%cinfo_hash=%s", a->scrape, strchr(a->scrape,'?')?'&':'?', tracker->escaped );
+ req->url = tr_strdup( ( char * ) EVBUFFER_DATA( url ) );
+ req->done_func = onScrapeResponse;
memcpy( req->torrent_hash, tracker->hash, SHA_DIGEST_LENGTH );
- addCommonHeaders( tracker, req->req );
+ evbuffer_free( url );
return req;
}
struct tr_tracker_handle
{
- int socketCount;
unsigned int isShuttingDown : 1;
+ int runningCount;
tr_timer * pulseTimer;
- tr_list * requestQueue;
- tr_list * scrapeQueue;
};
-static int pulse( void * vhandle );
+static int pulse( void * vsession );
static void
-ensureGlobalsExist( tr_handle * handle )
+ensureGlobalsExist( tr_session * session )
{
- if( handle->tracker == NULL )
+ if( session->tracker == NULL )
{
- handle->tracker = tr_new0( struct tr_tracker_handle, 1 );
- handle->tracker->pulseTimer = tr_timerNew( handle, pulse, handle, PULSE_INTERVAL_MSEC );
+ session->tracker = tr_new0( struct tr_tracker_handle, 1 );
+ session->tracker->pulseTimer = tr_timerNew( session, pulse, session, PULSE_INTERVAL_MSEC );
dbgmsg( NULL, "creating tracker timer" );
}
}
-static void
-freeRequest2( void * req )
-{
- freeRequest( req );
-}
-
void
-tr_trackerShuttingDown( tr_handle * handle )
+tr_trackerShuttingDown( tr_session * session )
{
- if( handle->tracker )
- {
- /* since we're shutting down, we don't need to scrape anymore... */
- tr_list_free( &handle->tracker->scrapeQueue, freeRequest2 );
-
- handle->tracker->isShuttingDown = 1;
- }
+ if( session->tracker )
+ session->tracker->isShuttingDown = 1;
}
static int
-maybeFreeGlobals( tr_handle * handle )
+maybeFreeGlobals( tr_session * session )
{
- int globalsExist = handle->tracker != NULL;
+ int globalsExist = session->tracker != NULL;
if( globalsExist
- && ( handle->tracker->socketCount < 1 )
- && ( handle->tracker->requestQueue == NULL )
- && ( handle->tracker->scrapeQueue == NULL )
- && ( handle->torrentList== NULL ) )
+ && ( session->tracker->runningCount < 1 )
+ && ( session->torrentList== NULL ) )
{
dbgmsg( NULL, "freeing tracker timer" );
- tr_timerFree( &handle->tracker->pulseTimer );
- tr_free( handle->tracker );
- handle->tracker = NULL;
+ tr_timerFree( &session->tracker->pulseTimer );
+ tr_free( session->tracker );
+ session->tracker = NULL;
globalsExist = FALSE;
}
****
***/
-static int
-freeConnection( void * evcon )
-{
- evhttp_connection_free( evcon );
- return FALSE;
-}
static void
-connectionClosedCB( struct evhttp_connection * evcon, void * vhandle )
+invokeRequest( void * vreq )
{
- tr_handle * handle = vhandle;
-
- /* libevent references evcon right after calling this function,
- so we can't free it yet... defer it to after this call chain
- has played out */
- tr_timerNew( handle, freeConnection, evcon, 100 );
-}
+ struct tr_tracker_request * req = vreq;
+ uint8_t * hash;
+ tr_tracker * t = findTracker( req->session, req->torrent_hash );
-static struct evhttp_connection*
-getConnection( tr_handle * handle, const char * address, int port )
-{
- struct evhttp_connection * c = evhttp_connection_new( address, port );
- evhttp_connection_set_closecb( c, connectionClosedCB, handle );
- return c;
-}
-
-static void
-invokeRequest( tr_handle * handle, const struct tr_tracker_request * req )
-{
- const time_t now = time( NULL );
- struct evhttp_connection * evcon = getConnection( handle, req->address, req->port );
- 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 );
- ++handle->tracker->socketCount;
-
- if( t != NULL )
+ if( t )
{
if( req->reqtype == TR_REQ_SCRAPE )
{
- t->lastScrapeTime = now;
+ t->lastScrapeTime = time( NULL );
t->scrapeAt = 0;
}
else
{
- t->lastAnnounceTime = now;
+ t->lastAnnounceTime = time( NULL );
t->reannounceAt = 0;
- t->manualAnnounceAllowedAt = 0;
+ t->manualAnnounceAllowedAt = ~(time_t)0;
}
}
- if( evhttp_make_request( evcon, req->req, EVHTTP_REQ_GET, req->uri ))
- (*req->req->cb)(req->req, req->req->cb_arg);
- else
- dbgmsg( t, "incremented socket count to %d", handle->tracker->socketCount );
-}
+ ++req->session->tracker->runningCount;
-static void
-invokeNextInQueue( tr_handle * handle, tr_list ** list )
-{
- struct tr_tracker_request * req = tr_list_pop_front( list );
- invokeRequest( handle, req );
- freeRequest( req );
-}
+ hash = tr_new0( uint8_t, SHA_DIGEST_LENGTH );
+ memcpy( hash, req->torrent_hash, SHA_DIGEST_LENGTH );
+ tr_webRun( req->session, req->url, req->done_func, hash );
-static int
-socketIsAvailable( tr_handle * handle )
-{
- const int max = handle->tracker->isShuttingDown
- ? MAX_TRACKER_SOCKETS_DURING_SHUTDOWN
- : MAX_TRACKER_SOCKETS;
- return handle->tracker->socketCount < max;
+ freeRequest( req );
}
-static void ensureGlobalsExist( tr_handle * );
+static void ensureGlobalsExist( tr_session * );
static void
-enqueueScrape( tr_handle * handle, const tr_tracker * tracker )
+enqueueScrape( tr_session * session, const tr_tracker * tracker )
{
struct tr_tracker_request * req;
- ensureGlobalsExist( handle );
- req = createScrape( handle, tracker );
- tr_list_append( &handle->tracker->scrapeQueue, req );
+ ensureGlobalsExist( session );
+ req = createScrape( session, tracker );
+ tr_runInEventThread( session, invokeRequest, req );
}
static void
-enqueueRequest( tr_handle * handle, const tr_tracker * tracker, int reqtype )
+enqueueRequest( tr_session * session, 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
-scrapeSoon( tr_tracker * t )
-{
- if( trackerSupportsScrape( t ) )
- t->scrapeAt = time( NULL ) + t->randOffset;
+ ensureGlobalsExist( session );
+ req = createRequest( session, tracker, reqtype );
+ tr_runInEventThread( session, invokeRequest, req );
}
static int
-pulse( void * vhandle )
+pulse( void * vsession )
{
- tr_handle * handle = vhandle;
- struct tr_tracker_handle * th = handle->tracker;
+ tr_session * session = vsession;
+ struct tr_tracker_handle * th = session->tracker;
tr_torrent * tor;
const time_t now = time( NULL );
- if( handle->tracker == NULL )
+ if( !session->tracker )
return FALSE;
- 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) );
+ if( th->runningCount )
+ dbgmsg( NULL, "tracker pulse... %d running", th->runningCount );
/* upkeep: queue periodic rescrape / reannounce */
- for( tor=handle->torrentList; tor; tor=tor->next )
+ for( tor=session->torrentList; tor; tor=tor->next )
{
tr_tracker * t = tor->tracker;
- if( t->scrapeAt && trackerSupportsScrape( t ) && ( now >= t->scrapeAt ) ) {
+ if( t->scrapeAt && trackerSupportsScrape( t, tor ) && ( now >= t->scrapeAt ) ) {
t->scrapeAt = 0;
- enqueueScrape( handle, t );
+ enqueueScrape( session, t );
}
if( t->reannounceAt && t->isRunning && ( now >= t->reannounceAt ) ) {
t->reannounceAt = 0;
- enqueueRequest( handle, t, TR_REQ_REANNOUNCE );
+ enqueueRequest( session, t, TR_REQ_REANNOUNCE );
}
}
- if( handle->tracker->socketCount || tr_list_size(th->requestQueue) || tr_list_size(th->scrapeQueue) )
- dbgmsg( NULL, "tracker pulse after upkeep... %d sockets, %d reqs left, %d scrapes left", handle->tracker->socketCount, tr_list_size(th->requestQueue), tr_list_size(th->scrapeQueue) );
-
- /* look for things to do... process all the requests, then process all the scrapes */
- while( th->requestQueue && socketIsAvailable( handle ) )
- invokeNextInQueue( handle, &th->requestQueue );
- while( th->scrapeQueue && socketIsAvailable( handle ) )
- invokeNextInQueue( handle, &th->scrapeQueue );
+ if( th->runningCount )
+ dbgmsg( NULL, "tracker pulse after upkeep... %d running", th->runningCount );
- if( handle->tracker->socketCount || tr_list_size(th->requestQueue) || tr_list_size(th->scrapeQueue) )
- dbgmsg( NULL, "tracker pulse done... %d sockets, %d reqs left, %d scrapes left", handle->tracker->socketCount, tr_list_size(th->requestQueue), tr_list_size(th->scrapeQueue) );
-
- return maybeFreeGlobals( handle );
+ return maybeFreeGlobals( session );
}
static void
-onReqDone( tr_handle * handle )
+onReqDone( tr_session * session )
{
- if( handle->tracker )
+ if( session->tracker )
{
- pulse( handle );
- --handle->tracker->socketCount;
- dbgmsg( NULL, "decrementing socket count to %d", handle->tracker->socketCount );
+ --session->tracker->runningCount;
+ dbgmsg( NULL, "decrementing runningCount to %d", session->tracker->runningCount );
+ pulse( session );
}
}
tr_trackerNew( const tr_torrent * torrent )
{
const tr_info * info = &torrent->info;
- int i, j, sum, *iwalk;
- tr_tracker_info * nwalk;
tr_tracker * t;
t = tr_new0( tr_tracker, 1 );
- t->handle = torrent->handle;
- t->scrapeIntervalSec = DEFAULT_SCRAPE_INTERVAL_SEC;
- t->retryScrapeIntervalSec = 60;
- t->announceIntervalSec = DEFAULT_ANNOUNCE_INTERVAL_SEC;
- t->announceMinIntervalSec = DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC;
- generateKeyParam( t->key_param, KEYLEN );
-
t->publisher = tr_publisherNew( );
- t->timesDownloaded = -1;
- t->seederCount = -1;
- t->leecherCount = -1;
- t->manualAnnounceAllowedAt = ~(time_t)0;
+ t->session = torrent->handle;
+ t->scrapeIntervalSec = DEFAULT_SCRAPE_INTERVAL_SEC;
+ t->retryScrapeIntervalSec = 60;
+ t->announceIntervalSec = DEFAULT_ANNOUNCE_INTERVAL_SEC;
+ t->announceMinIntervalSec = DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC;
+ t->timesDownloaded = -1;
+ t->seederCount = -1;
+ t->leecherCount = -1;
+ t->manualAnnounceAllowedAt = ~(time_t)0;
t->name = tr_strdup( info->name );
t->randOffset = tr_rand( 120 );
memcpy( t->hash, info->hash, SHA_DIGEST_LENGTH );
escape( t->escaped, info->hash, SHA_DIGEST_LENGTH );
+ generateKeyParam( t->key_param, KEYLEN );
- for( sum=i=0; i<info->trackerTiers; ++i )
- sum += info->trackerList[i].count;
- t->addresses = nwalk = tr_new0( tr_tracker_info, sum );
- t->addressIndex = 0;
- t->addressCount = sum;
- t->tierFronts = iwalk = tr_new0( int, sum );
-
- for( i=0; i<info->trackerTiers; ++i )
- {
- const int tierFront = nwalk - t->addresses;
-
- for( j=0; j<info->trackerList[i].count; ++j )
- {
- const tr_tracker_info * src = &info->trackerList[i].list[j];
- nwalk->address = tr_strdup( src->address );
- nwalk->port = src->port;
- nwalk->announce = tr_strdup( src->announce );
- nwalk->scrape = tr_strdup( src->scrape );
- ++nwalk;
-
- *iwalk++ = tierFront;
- }
- }
-
- assert( nwalk - t->addresses == sum );
- assert( iwalk - t->tierFronts == sum );
+ t->trackerIndex = 0;
- scrapeSoon( t );
+ if( trackerSupportsScrape( t, torrent ) )
+ t->scrapeAt = time( NULL ) + t->randOffset;
return t;
}
static void
onTrackerFreeNow( void * vt )
{
- int i;
tr_tracker * t = vt;
tr_publisherFree( &t->publisher );
tr_free( t->trackerID );
tr_free( t->peer_id );
- /* addresses... */
- for( i=0; i<t->addressCount; ++i )
- tr_trackerInfoClear( &t->addresses[i] );
- tr_free( t->addresses );
- tr_free( t->tierFronts );
-
- /* redirect... */
- if( t->redirect ) {
- tr_trackerInfoClear( t->redirect );
- tr_free( t->redirect );
- }
-
tr_free( t );
}
tr_trackerFree( tr_tracker * t )
{
if( t )
- tr_runInEventThread( t->handle, onTrackerFreeNow, t );
+ tr_runInEventThread( t->session, onTrackerFreeNow, t );
}
tr_publisher_tag
void
tr_trackerStart( tr_tracker * t )
{
- if( t )
+ if( t && !t->isRunning )
{
tr_free( t->peer_id );
t->peer_id = tr_peerIdNew( );
- if( t->isRunning == 0 ) {
- t->isRunning = 1;
- enqueueRequest( t->handle, t, TR_REQ_STARTED );
- }
+ t->isRunning = 1;
+ enqueueRequest( t->session, t, TR_REQ_STARTED );
}
}
void
tr_trackerReannounce( tr_tracker * t )
{
- enqueueRequest( t->handle, t, TR_REQ_REANNOUNCE );
+ enqueueRequest( t->session, t, TR_REQ_REANNOUNCE );
}
void
tr_trackerCompleted( tr_tracker * t )
{
- enqueueRequest( t->handle, t, TR_REQ_COMPLETED );
+ enqueueRequest( t->session, t, TR_REQ_COMPLETED );
}
void
tr_trackerStop( tr_tracker * t )
{
+fprintf( stderr, "trackerStop... isRunning %d\n", (int)t->isRunning );
if( t && t->isRunning ) {
t->isRunning = 0;
t->reannounceAt = t->manualAnnounceAllowedAt = 0;
- enqueueRequest( t->handle, t, TR_REQ_STOPPED );
+ enqueueRequest( t->session, t, TR_REQ_STOPPED );
}
}
}
void
-tr_trackerStat( const tr_tracker * t,
+tr_trackerStat( const tr_tracker * t,
struct tr_tracker_stat * setme)
{
assert( t != NULL );
assert( setme != NULL );
- strlcpy( setme->scrapeResponse,
- t->lastScrapeResponse,
- sizeof( setme->scrapeResponse ) );
+ snprintf( setme->scrapeResponse,
+ sizeof( setme->scrapeResponse ),
+ "%ld", t->lastScrapeResponse );
setme->lastScrapeTime = t->lastScrapeTime;
setme->nextScrapeTime = t->scrapeAt;
- strlcpy( setme->announceResponse,
- t->lastAnnounceResponse,
- sizeof( setme->announceResponse ) );
+ snprintf( setme->announceResponse,
+ sizeof( setme->announceResponse ),
+ "%ld", t->lastAnnounceResponse );
+
setme->lastAnnounceTime = t->lastAnnounceTime;
setme->nextAnnounceTime = t->reannounceAt;
setme->nextManualAnnounceTime = t->manualAnnounceAllowedAt;