Changeset 3451


Ignore:
Timestamp:
Oct 17, 2007, 6:59:58 PM (14 years ago)
Author:
charles
Message:

huge tracker cleanup for the "no response from tracker" issue

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/NEWS

    r3371 r3451  
    66 - Only report downloaded, verified good pieces in tracker `download' field
    77 - Improved compliance with BitTorrent spec
    8  - Multiscrape support
    98 - Significant rewrite of the libtransmission back-end
    109 - OS X:
  • trunk/libtransmission/torrent.c

    r3426 r3451  
    147147onTrackerResponse( void * tracker UNUSED, void * vevent, void * user_data )
    148148{
    149     tr_torrent * tor = (tr_torrent *) user_data;
    150     tr_tracker_event_t * event = (tr_tracker_event_t *) vevent;
     149    tr_torrent * tor = user_data;
     150    tr_tracker_event * event = vevent;
    151151
    152152    switch( event->messageType )
  • trunk/libtransmission/tracker.c

    r3439 r3451  
    1313#include <assert.h>
    1414#include <ctype.h> /* isalnum */
    15 #include <limits.h> /* INT_MAX */
    1615#include <stdio.h> /* snprintf */
    1716#include <stdlib.h>
    1817#include <string.h> /* strcmp, strchr */
    19 #include <sys/queue.h> /* for evhttp */
    20 #include <sys/types.h> /* for evhttp */
    21 
     18
     19#include <sys/queue.h> /* libevent needs this */
     20#include <sys/types.h> /* libevent needs this */
    2221#include <event.h>
    2322#include <evhttp.h>
     
    2726#include "completion.h"
    2827#include "net.h"
    29 #include "ptrarray.h"
    3028#include "publish.h"
    3129#include "shared.h"
     
    3432#include "utils.h"
    3533
    36 #define MINUTES_TO_MSEC(N) ((N) * 60 * 1000)
    37 
    38 /* we follow uTorrent 1.8's lead of allowing a manual reannounce
    39  * every MAX( 60 seconds, min_interval ) */
    40 #define DEFAULT_MANUAL_ANNOUNCE_INTERVAL_SEC (60)
    41 
    42 /* unless the tracker tells us otherwise, rescrape this frequently */
    43 #define DEFAULT_SCRAPE_INTERVAL_SEC (60*15)
    44 
    45 /* unless the tracker tells us otherwise, this is the announce interval */
    46 #define DEFAULT_ANNOUNCE_INTERVAL_SEC (240)
    47 
    48 /* unless the tracker tells us otherwise, this is the announce min_interval */
    49 #define DEFAULT_MIN_ANNOUNCE_INTERVAL_SEC (30)
    50 
    51 /* this is how long we'll leave a request hanging before timeout */
    52 #define TIMEOUT_INTERVAL_SEC 40
    53 #define STOPPING_TIMEOUT_INTERVAL_SEC 8
    54 
    55 /* the value of the 'numwant' argument passed in tracker requests.
    56  * this should be big, but if it's *too* big trackers will ignore it */
    57 #define NUMWANT 256
    58 
    59 /* the length of the 'key' argument passed in tracker requests */
    60 #define TR_KEY_LEN 10
    61 
     34enum
     35{
     36    /* unless the tracker says otherwise, rescrape this frequently */
     37    DEFAULT_SCRAPE_INTERVAL_SEC = (60 * 15),
     38
     39    /* unless the tracker says otherwise, this is the announce interval */
     40    DEFAULT_ANNOUNCE_INTERVAL_SEC = (60 * 4),
     41
     42    /* unless the tracker says otherwise, this is the announce min_interval */
     43    DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC = (60 * 2),
     44
     45    /* this is how long we'll leave a request hanging before timeout */
     46    TIMEOUT_INTERVAL_SEC = 45,
     47
     48    /* this is how long we'll leave a 'stop' request hanging before timeout.
     49       we wait less time for this so it doesn't slow down shutdowns */
     50    STOP_TIMEOUT_INTERVAL_SEC = 5,
     51
     52    /* the value of the 'numwant' argument passed in tracker requests. */
     53    NUMWANT = 200,
     54
     55    /* the length of the 'key' argument passed in tracker requests */
     56    KEYLEN = 10
     57};
    6258
    6359/**
     
    6561**/
    6662
    67 typedef struct
     63struct tr_tracker
    6864{
    6965    tr_handle * handle;
    70 
    71     tr_ptrArray * torrents;
    72     tr_ptrArray * scraping;
    73     tr_ptrArray * scrapeQueue;
    7466
    7567    /* these are set from the latest scrape or tracker response */
    7668    int announceIntervalSec;
    77     int minAnnounceIntervalSec;
     69    int announceMinIntervalSec;
    7870    int scrapeIntervalSec;
    79 
    80     /* calculated when we get fewer scrapes
    81        back than we asked for */
    82     int multiscrapeMax;
    8371
    8472    tr_tracker_info * redirect;
     
    8876    int * tierFronts;
    8977
    90     char * primaryAddress;
    91 
    9278    /* sent as the "key" argument in tracker requests
    9379       to verify us if our IP address changes.
    9480       This is immutable for the life of the tracker object. */
    95     char key_param[TR_KEY_LEN+1];
    96 
    97     tr_timer * scrapeTimer;
    98 }
    99 Tracker;
    100 
    101 /* this is the Torrent struct, but since it's the pointer
    102    passed around in the public API of this tracker module,
    103    its *public* name is tr_tracker... wheee */
    104 typedef struct tr_tracker
    105 {
     81    char key_param[KEYLEN+1];
     82
    10683    tr_publisher_t * publisher;
    10784
     
    11895    char peer_id[TR_ID_LEN + 1];
    11996
    120     /* these are set from the latest scrape or tracker response...
    121        -1 means 'unknown' */
     97    /* these are set from the latest tracker response... -1 is 'unknown' */
    12298    int timesDownloaded;
    123     int seeders;
    124     int leechers;
     99    int seederCount;
     100    int leecherCount;
    125101    char * trackerID;
    126102
     
    132108    time_t manualAnnounceAllowedAt;
    133109
    134     Tracker * tracker;
    135 
    136110    tr_timer * scrapeTimer;
    137111    tr_timer * reannounceTimer;
    138112
    139113    unsigned int isRunning : 1;
    140 }
    141 Torrent;
    142 
    143 static int
    144 trackerCompare( const void * va, const void * vb )
    145 {
    146     const Tracker * a = ( const Tracker * ) va;
    147     const Tracker * b = ( const Tracker * ) vb;
    148     return strcmp( a->primaryAddress, b->primaryAddress );
    149 }
    150 
    151 static int
    152 torrentCompare( const void * va, const void * vb )
    153 {
    154     const Torrent * a = (const Torrent*) va;
    155     const Torrent * b = (const Torrent*) vb;
    156     return memcmp( a->hash, b->hash, SHA_DIGEST_LENGTH );
    157 }
     114};
    158115
    159116/***
    160 ****
     117****  Connections that know how to clean up after themselves
    161118***/
    162119
     
    171128connectionClosedCB( struct evhttp_connection * evcon, void * handle )
    172129{
     130    /* libevent references evcon right after calling this function,
     131       so we can't free it yet... defer it to after this call chain
     132       has played out */
    173133    tr_timerNew( handle, freeConnection, evcon, 100 );
    174134}
    175135
    176136static struct evhttp_connection*
    177 getConnection( Tracker * tracker, const char * address, int port )
     137getConnection( tr_tracker * t, const char * address, int port )
    178138{
    179139    struct evhttp_connection * c = evhttp_connection_new( address, port );
    180     evhttp_connection_set_closecb( c, connectionClosedCB, tracker->handle );
     140    evhttp_connection_set_closecb( c, connectionClosedCB, t->handle );
    181141    return c;
    182142}
     
    186146***/
    187147
    188 static const tr_tracker_event_t emptyEvent = { 0, NULL, NULL, NULL, 0 };
    189 
    190 static void
    191 publishMessage( Torrent * tor, const char * msg, int type )
    192 {
    193     tr_tracker_event_t event = emptyEvent;
    194     event.hash = tor->hash;
     148static const tr_tracker_event emptyEvent = { 0, NULL, NULL, NULL, 0 };
     149
     150static void
     151publishMessage( tr_tracker * t, const char * msg, int type )
     152{
     153    tr_tracker_event event = emptyEvent;
     154    event.hash = t->hash;
    195155    event.messageType = type;
    196156    event.text = msg;
    197     tr_publisherPublish( tor->publisher, tor, &event );
    198 }
    199 
    200 static void
    201 publishErrorClear( Torrent * tor )
    202 {
    203     publishMessage( tor, NULL, TR_TRACKER_ERROR_CLEAR );
    204 }
    205 
    206 static void
    207 publishErrorMessage( Torrent * tor, const char * msg )
    208 {
    209     publishMessage( tor, msg, TR_TRACKER_ERROR );
    210 }
    211 
    212 static void
    213 publishWarningMessage( Torrent * tor, const char * msg )
    214 {
    215     publishMessage( tor, msg, TR_TRACKER_WARNING );
    216 }
    217 
    218 static void
    219 publishNewPeers( Torrent * tor, int count, uint8_t * peers )
    220 {
    221     tr_tracker_event_t event = emptyEvent;
    222     event.hash = tor->hash;
     157    tr_publisherPublish( t->publisher, t, &event );
     158}
     159
     160static void
     161publishErrorClear( tr_tracker * t )
     162{
     163    publishMessage( t, NULL, TR_TRACKER_ERROR_CLEAR );
     164}
     165
     166static void
     167publishErrorMessage( tr_tracker * t, const char * msg )
     168{
     169    publishMessage( t, msg, TR_TRACKER_ERROR );
     170}
     171
     172static void
     173publishWarning( tr_tracker * t, const char * msg )
     174{
     175    publishMessage( t, msg, TR_TRACKER_WARNING );
     176}
     177
     178static void
     179publishNewPeers( tr_tracker * t, int count, uint8_t * peers )
     180{
     181    tr_tracker_event event = emptyEvent;
     182    event.hash = t->hash;
    223183    event.messageType = TR_TRACKER_PEERS;
    224184    event.peerCount = count;
    225185    event.peerCompact = peers;
    226     tr_inf( "Torrent \"%s\" got %d new peers", tor->name, count );
    227     tr_publisherPublish( tor->publisher, tor, &event );
     186    tr_inf( "Torrent \"%s\" got %d new peers", t->name, count );
     187    tr_publisherPublish( t->publisher, t, &event );
    228188}
    229189
     
    232192***/
    233193
    234 static tr_ptrArray *
    235 getTrackerLookupTable( void )
    236 {
    237     static tr_ptrArray * myTrackers = NULL;
    238     if( !myTrackers )
    239          myTrackers = tr_ptrArrayNew( );
    240     return myTrackers;
    241 }
    242 
    243194static void
    244195generateKeyParam( char * msg, int len )
     
    246197    int i;
    247198    const char * pool = "abcdefghijklmnopqrstuvwxyz0123456789";
     199    const int poolSize = strlen( pool );
    248200    for( i=0; i<len; ++i )
    249         *msg++ = pool[tr_rand(36)];
     201        *msg++ = pool[tr_rand(poolSize)];
    250202    *msg = '\0';
    251 }
    252 
    253 static int onTrackerScrapeNow( void* );
    254 
    255 static void
    256 tr_trackerScrapeSoon( Tracker * t )
    257 {
    258     /* don't start more than one scrape at once for the same tracker... */
    259     if( !tr_ptrArrayEmpty( t->scraping ) )
    260         return;
    261 
    262     if( !t->scrapeTimer )
    263          t->scrapeTimer = tr_timerNew( t->handle, onTrackerScrapeNow, t, 5000 );
    264 }
    265 
    266 static Tracker*
    267 getExistingTracker( const char * primaryAddress )
    268 {
    269     tr_ptrArray * trackers = getTrackerLookupTable( );
    270     Tracker tmp;
    271     assert( primaryAddress && *primaryAddress );
    272     tmp.primaryAddress = (char*) primaryAddress;
    273     return tr_ptrArrayFindSorted( trackers, &tmp, trackerCompare );
    274 }
    275 
    276 static Tracker*
    277 tr_trackerGet( const tr_torrent * tor )
    278 {
    279     const tr_info * info = &tor->info;
    280     Tracker * t = getExistingTracker( info->primaryAddress );
    281 
    282     if( t == NULL ) /* no such tracker.... create one */
    283     {
    284         int i, j, sum, *iwalk;
    285         tr_tracker_info * nwalk;
    286         tr_dbg( "making a new tracker for \"%s\"", info->primaryAddress );
    287 
    288         t = tr_new0( Tracker, 1 );
    289         t->handle = tor->handle;
    290         t->primaryAddress = tr_strdup( info->primaryAddress );
    291         t->scrapeIntervalSec       = DEFAULT_SCRAPE_INTERVAL_SEC;
    292         t->announceIntervalSec     = DEFAULT_ANNOUNCE_INTERVAL_SEC;
    293         t->minAnnounceIntervalSec  = DEFAULT_MIN_ANNOUNCE_INTERVAL_SEC;
    294         t->multiscrapeMax = INT_MAX;
    295         t->torrents    = tr_ptrArrayNew( );
    296         t->scraping    = tr_ptrArrayNew( );
    297         t->scrapeQueue = tr_ptrArrayNew( );
    298         generateKeyParam( t->key_param, TR_KEY_LEN );
    299 
    300         for( sum=i=0; i<info->trackerTiers; ++i )
    301              sum += info->trackerList[i].count;
    302         t->addresses = nwalk = tr_new0( tr_tracker_info, sum );
    303         t->addressIndex = 0;
    304         t->addressCount = sum;
    305         t->tierFronts = iwalk = tr_new0( int, sum );
    306 
    307         for( i=0; i<info->trackerTiers; ++i )
    308         {
    309             const int tierFront = nwalk - t->addresses;
    310 
    311             for( j=0; j<info->trackerList[i].count; ++j )
    312             {
    313                 const tr_tracker_info * src = &info->trackerList[i].list[j];
    314                 nwalk->address = tr_strdup( src->address );
    315                 nwalk->port = src->port;
    316                 nwalk->announce = tr_strdup( src->announce );
    317                 nwalk->scrape = tr_strdup( src->scrape );
    318                 ++nwalk;
    319 
    320                 *iwalk++ = tierFront;
    321             }
    322         }
    323 
    324         assert( nwalk - t->addresses == sum );
    325         assert( iwalk - t->tierFronts == sum );
    326 
    327         tr_ptrArrayInsertSorted( getTrackerLookupTable( ), t, trackerCompare );
    328     }
    329 
    330     return t;
    331 }
    332 
    333 static Torrent *
    334 getExistingTorrent( Tracker * t, const uint8_t hash[SHA_DIGEST_LENGTH] )
    335 {
    336     Torrent tmp;
    337     memcpy( tmp.hash, hash, SHA_DIGEST_LENGTH );
    338     return tr_ptrArrayFindSorted( t->torrents, &tmp, torrentCompare );
    339203}
    340204
     
    351215}
    352216
    353 static void
    354 onTorrentFreeNow( void * vtor )
    355 {
    356     Torrent * tor = (Torrent *) vtor;
    357     Tracker * t = tor->tracker;
    358 
    359     tr_ptrArrayRemoveSorted( t->torrents, tor, torrentCompare );
    360     tr_ptrArrayRemoveSorted( t->scrapeQueue, tor, torrentCompare );
    361     tr_ptrArrayRemoveSorted( t->scraping, tor, torrentCompare );
    362 
    363     tr_timerFree( &tor->scrapeTimer );
    364     tr_timerFree( &tor->reannounceTimer );
    365     tr_publisherFree( &tor->publisher );
    366     tr_free( tor->name );
    367     tr_free( tor->trackerID );
    368     tr_free( tor->lastRequest );
    369     tr_free( tor );
    370 
    371     if( tr_ptrArrayEmpty( t->torrents ) ) /* last one.. free the tracker too */
    372     {
    373         int i;
    374         tr_ptrArrayRemoveSorted( getTrackerLookupTable( ), t, trackerCompare );
    375 
    376         tr_ptrArrayFree( t->torrents, NULL );
    377         tr_ptrArrayFree( t->scrapeQueue, NULL );
    378         tr_ptrArrayFree( t->scraping, NULL );
    379 
    380         for( i=0; i<t->addressCount; ++i )
    381             tr_trackerInfoClear( &t->addresses[i] );
    382 
    383         if( t->redirect ) {
    384             tr_trackerInfoClear( t->redirect );
    385             tr_free( t->redirect );
     217static void scrapeNow( tr_tracker * );
     218
     219tr_tracker *
     220tr_trackerNew( const tr_torrent * torrent )
     221{
     222    const tr_info * info = &torrent->info;
     223    int i, j, sum, *iwalk;
     224    tr_tracker_info * nwalk;
     225    tr_tracker * t;
     226
     227    tr_dbg( "making a new tracker for \"%s\"", info->primaryAddress );
     228
     229    t = tr_new0( tr_tracker, 1 );
     230    t->handle = torrent->handle;
     231    t->scrapeIntervalSec       = DEFAULT_SCRAPE_INTERVAL_SEC;
     232    t->announceIntervalSec     = DEFAULT_ANNOUNCE_INTERVAL_SEC;
     233    t->announceMinIntervalSec  = DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC;
     234    generateKeyParam( t->key_param, KEYLEN );
     235
     236    t->publisher = tr_publisherNew( );
     237    t->timesDownloaded = -1;
     238    t->seederCount = -1;
     239    t->leecherCount = -1;
     240    t->manualAnnounceAllowedAt = ~(time_t)0;
     241    t->name = tr_strdup( info->name );
     242    memcpy( t->hash, info->hash, SHA_DIGEST_LENGTH );
     243    escape( t->escaped, info->hash, SHA_DIGEST_LENGTH );
     244
     245    for( sum=i=0; i<info->trackerTiers; ++i )
     246         sum += info->trackerList[i].count;
     247    t->addresses = nwalk = tr_new0( tr_tracker_info, sum );
     248    t->addressIndex = 0;
     249    t->addressCount = sum;
     250    t->tierFronts = iwalk = tr_new0( int, sum );
     251
     252    for( i=0; i<info->trackerTiers; ++i )
     253    {
     254        const int tierFront = nwalk - t->addresses;
     255
     256        for( j=0; j<info->trackerList[i].count; ++j )
     257        {
     258            const tr_tracker_info * src = &info->trackerList[i].list[j];
     259            nwalk->address = tr_strdup( src->address );
     260            nwalk->port = src->port;
     261            nwalk->announce = tr_strdup( src->announce );
     262            nwalk->scrape = tr_strdup( src->scrape );
     263            ++nwalk;
     264
     265            *iwalk++ = tierFront;
    386266        }
    387 
    388         tr_timerFree( &t->scrapeTimer );
    389 
    390         tr_free( t->primaryAddress );
    391         tr_free( t->addresses );
    392         tr_free( t->tierFronts );
    393         tr_free( t );
    394     }
     267    }
     268
     269    assert( nwalk - t->addresses == sum );
     270    assert( iwalk - t->tierFronts == sum );
     271
     272    scrapeNow( t );
     273fprintf( stderr, "sizeof(tr_tracker) is %d\n", (int)sizeof(tr_tracker) );
     274    return t;
     275}
     276
     277static void
     278onTrackerFreeNow( void * vt )
     279{
     280    int i;
     281    tr_tracker * t = vt;
     282
     283    tr_timerFree( &t->scrapeTimer );
     284    tr_timerFree( &t->reannounceTimer );
     285    tr_publisherFree( &t->publisher );
     286    tr_free( t->name );
     287    tr_free( t->trackerID );
     288    tr_free( t->lastRequest );
     289
     290    for( i=0; i<t->addressCount; ++i )
     291        tr_trackerInfoClear( &t->addresses[i] );
     292
     293    if( t->redirect ) {
     294        tr_trackerInfoClear( t->redirect );
     295        tr_free( t->redirect );
     296    }
     297
     298    tr_timerFree( &t->scrapeTimer );
     299
     300    tr_free( t->addresses );
     301    tr_free( t->tierFronts );
     302    tr_free( t );
    395303}
    396304
    397305void
    398 tr_trackerFree( Torrent * tor )
    399 {
    400     tr_runInEventThread( tor->tracker->handle, onTorrentFreeNow, tor );
    401 }
    402 
    403 Torrent*
    404 tr_trackerNew( tr_torrent * torrent )
    405 {
    406     Torrent * tor;
    407     Tracker * t = tr_trackerGet( torrent );
    408     assert( getExistingTorrent( t, torrent->info.hash ) == NULL );
    409 
    410     /* create a new Torrent and queue it for scraping */
    411     tor = tr_new0( Torrent, 1 );
    412     tor->publisher = tr_publisherNew( );
    413     tor->tracker = t;
    414     /*tor->torrent = torrent;*/
    415     tor->timesDownloaded = -1;
    416     tor->seeders = -1;
    417     tor->leechers = -1;
    418     tor->manualAnnounceAllowedAt = ~0;
    419     tor->name = tr_strdup( torrent->info.name );
    420     memcpy( tor->hash, torrent->info.hash, SHA_DIGEST_LENGTH );
    421     escape( tor->escaped, torrent->info.hash, SHA_DIGEST_LENGTH );
    422     tr_ptrArrayInsertSorted( t->torrents, tor, torrentCompare );
    423     tr_ptrArrayInsertSorted( t->scrapeQueue, tor, torrentCompare );
    424     tr_trackerScrapeSoon( t );
    425     return tor;
     306tr_trackerFree( tr_tracker * t )
     307{
     308    tr_runInEventThread( t->handle, onTrackerFreeNow, t );
    426309}
    427310
     
    441324        if( !tr_bencLoad( body+i, bodylen-1, setme, NULL ) )
    442325            ret = 0;
     326
    443327    return ret;
    444328}
    445329
    446 static char*
    447 updateAddresses( Tracker * t, const struct evhttp_request * req )
    448 {
    449     char * ret = NULL;
     330static const char*
     331updateAddresses( tr_tracker * t, const struct evhttp_request * req )
     332{
     333    const char * ret = NULL;
    450334    int moveToNextAddress = FALSE;
    451335
    452336    if( !req )
    453337    {
    454         ret = tr_strdup( "No response from tracker -- will keep trying." );
     338        ret = "No response from tracker -- will keep trying.";
    455339        tr_inf( ret );
    456340
     
    496380    else
    497381    {
    498         ret = tr_strdup( "No response from tracker -- will keep trying." );
     382        ret = "No response from tracker -- will keep trying.";
    499383        moveToNextAddress = TRUE;
    500384    }
     
    508392
    509393static tr_tracker_info *
    510 getCurrentAddress( const Tracker * t )
     394getCurrentAddress( const tr_tracker * t )
    511395{
    512396    assert( t->addresses != NULL );
     
    517401}
    518402static int
    519 trackerSupportsScrape( const Tracker * t )
     403trackerSupportsScrape( const tr_tracker * t )
    520404{
    521405    const tr_tracker_info * info = getCurrentAddress( t );
     
    528412
    529413static void
    530 addCommonHeaders( const Tracker * t,
     414addCommonHeaders( const tr_tracker * t,
    531415                  struct evhttp_request * req )
    532416{
    533417    char buf[1024];
    534     tr_tracker_info * address = getCurrentAddress( t );
     418    const tr_tracker_info * address = getCurrentAddress( t );
    535419    snprintf( buf, sizeof(buf), "%s:%d", address->address, address->port );
    536420    evhttp_add_header( req->output_headers, "Host", buf );
     
    552436
    553437static struct torrent_hash*
    554 torrentHashNew( Torrent * tor )
     438torrentHashNew( tr_tracker * t )
    555439{
    556440    struct torrent_hash * data = tr_new( struct torrent_hash, 1 );
    557     data->handle = tor->tracker->handle;
    558     memcpy( data->hash, tor->hash, SHA_DIGEST_LENGTH );
     441    data->handle = t->handle;
     442    memcpy( data->hash, t->hash, SHA_DIGEST_LENGTH );
    559443    return data;
    560444}
    561445
    562 tr_torrent*
    563 findTorrentFromHash( struct torrent_hash * data )
    564 {
    565     return tr_torrentFindFromHash( data->handle, data->hash );
     446tr_tracker *
     447findTrackerFromHash( struct torrent_hash * data )
     448{
     449    tr_torrent * torrent = tr_torrentFindFromHash( data->handle, data->hash );
     450    return torrent ? torrent->tracker : NULL;
    566451}
    567452
     
    573458
    574459static int
    575 onTorrentScrapeNow( void * vhash )
    576 {
    577     tr_torrent * torrent = findTorrentFromHash( vhash );
     460onScrapeNow( void * vt );
     461
     462static void
     463onScrapeResponse( struct evhttp_request * req, void * vhash )
     464{
     465    const char * warning;
     466    time_t nextScrapeSec = 60;
     467    tr_tracker * t;
     468
     469    t = findTrackerFromHash( vhash );
    578470    tr_free( vhash );
    579 
    580     if( torrent != NULL )
    581     {
    582         Torrent * tor = torrent->tracker;
    583         if( trackerSupportsScrape( tor->tracker ) )
    584         {
    585             if( tr_ptrArrayFindSorted( tor->tracker->scrapeQueue, tor, torrentCompare) == NULL )
    586                 tr_ptrArrayInsertSorted( tor->tracker->scrapeQueue, tor, torrentCompare );
    587             tr_trackerScrapeSoon( tor->tracker );
    588         }
    589         tor->scrapeTimer = NULL;
    590     }
    591     return FALSE;
    592 }
    593 
    594 static void
    595 onScrapeResponse( struct evhttp_request * req, void * primaryAddress )
    596 {
    597     char * errmsg;
    598     Tracker * t;
    599 
    600     tr_inf( "Got scrape response from  '%s': %s",
    601             primaryAddress,
    602             ( ( req && req->response_code_line ) ? req->response_code_line : "(null)") );
    603 
    604     t = getExistingTracker( primaryAddress );
    605     tr_free( primaryAddress );
    606     if( t == NULL ) /* tracker has been closed... */
     471    if( t == NULL ) /* tracker's been closed... */
    607472        return;
    608473
     474    tr_inf( "Got scrape response for  '%s': %s",
     475            t->name,
     476            ( ( req && req->response_code_line ) ? req->response_code_line
     477                                                 : "(null)") );
     478
    609479    if( req && ( req->response_code == HTTP_OK ) )
    610480    {
    611         int numResponses = 0;
    612481        benc_val_t benc, *files;
    613         const int n_scraping = tr_ptrArraySize( t->scraping );
    614482        const int bencLoaded = !parseBencResponse( req, &benc );
    615483
     
    622490            {
    623491                const uint8_t* hash =
    624                     (const uint8_t*) files->val.l.vals[i].val.s.s;
     492                        (const uint8_t*) files->val.l.vals[i].val.s.s;
    625493                benc_val_t *tmp, *flags;
    626494                benc_val_t *tordict = &files->val.l.vals[i+1];
    627                 Torrent * tor = getExistingTorrent( t, hash );
    628                 ++numResponses;
    629                    
    630                 if( !tor )
     495                if( memcmp( t->hash, hash, SHA_DIGEST_LENGTH ) )
    631496                    continue;
    632497
    633                 publishErrorClear( tor );
     498                publishErrorClear( t );
    634499
    635500                if(( tmp = tr_bencDictFind( tordict, "complete" )))
    636                     tor->seeders = tmp->val.i;
     501                    t->seederCount = tmp->val.i;
    637502
    638503                if(( tmp = tr_bencDictFind( tordict, "incomplete" )))
    639                     tor->leechers = tmp->val.i;
     504                    t->leecherCount = tmp->val.i;
    640505
    641506                if(( tmp = tr_bencDictFind( tordict, "downloaded" )))
    642                     tor->timesDownloaded = tmp->val.i;
     507                    t->timesDownloaded = tmp->val.i;
    643508
    644509                if(( flags = tr_bencDictFind( tordict, "flags" )))
     
    646511                        t->scrapeIntervalSec = tmp->val.i;
    647512
    648                 tr_ptrArrayRemoveSorted( t->scraping, tor, torrentCompare );
    649 
    650                 tr_timerFree( &tor->scrapeTimer );
    651                 tor->scrapeTimer = tr_timerNew( t->handle, onTorrentScrapeNow, torrentHashNew(tor), t->scrapeIntervalSec*1000 );
    652513                tr_dbg( "Torrent '%s' scrape successful."
    653514                        "  Rescraping in %d seconds",
    654                         tor->name, t->scrapeIntervalSec );
    655             }
    656 
    657             if( !files->val.l.count )
    658             {
    659                 /* got an empty files dictionary!  This probably means the
    660                    torrents we're scraping have expired from the tracker,
    661                    so make sure they're stopped.  It also means any previous
    662                    changes to multiscrapeMax are suspect, so reset that. */
    663 
    664                 int n;
    665                 Torrent ** torrents = (Torrent**)
    666                     tr_ptrArrayPeek( t->scraping, &n );
    667                 for( i=0; i<n; ++i )
    668                     tr_trackerStop( torrents[i] );
    669                 tr_ptrArrayClear( t->scraping );
    670 
    671                 t->multiscrapeMax = INT_MAX;
     515                        t->name, t->scrapeIntervalSec );
     516
     517                nextScrapeSec = t->scrapeIntervalSec;
    672518            }
    673519        }
     
    675521        if( bencLoaded )
    676522            tr_bencFree( &benc );
    677 
    678         /* if the tracker gave us back fewer torrents than we
    679            thought we should get, maybe our multiscrape string
    680            is too big... limit it based on how many we got back */
    681         if( ( 0 < numResponses ) && ( numResponses < n_scraping ) )
    682             t->multiscrapeMax = numResponses;
    683     }
    684 
    685     if (( errmsg = updateAddresses( t, req ) ))
    686         tr_err( errmsg );
    687 
    688     if( !tr_ptrArrayEmpty( t->scraping ) )
    689     {
    690         int i, n;
    691         Torrent ** torrents =
    692             (Torrent**) tr_ptrArrayPeek( t->scraping, &n );
    693         for( i=0; i<n; ++i ) {
    694             if( errmsg != NULL )
    695                 publishErrorMessage( torrents[i], errmsg );
    696             onTorrentScrapeNow( torrentHashNew(torrents[i]) );
    697         }
    698         tr_ptrArrayClear( t->scraping );
    699     }
    700     tr_free( errmsg );
    701 
    702     if( !tr_ptrArrayEmpty( t->scrapeQueue ) )
    703         tr_trackerScrapeSoon( t );
     523    }
     524
     525    if (( warning = updateAddresses( t, req ) )) {
     526        tr_err( warning );
     527        publishWarning( t, warning );
     528    }
     529
     530    tr_timerFree( &t->scrapeTimer );
     531
     532    t->scrapeTimer = tr_timerNew( t->handle,
     533                                  onScrapeNow, t,
     534                                  nextScrapeSec*1000 );
    704535}
    705536
    706537static int
    707 onTrackerScrapeNow( void * vt )
    708 {
    709     Tracker * t = (Tracker*) vt;
     538onScrapeNow( void * vt )
     539{
     540    tr_tracker * t = vt;
    710541    const tr_tracker_info * address = getCurrentAddress( t );
    711542
    712     assert( tr_ptrArrayEmpty( t->scraping ) );
    713 
    714     if( trackerSupportsScrape( t ) && !tr_ptrArrayEmpty( t->scrapeQueue ) )
    715     {
    716         int i, n, len, addr_len, ask_n;
    717         char *march, *uri;
    718         Torrent ** torrents =
    719             (Torrent**) tr_ptrArrayPeek( t->scrapeQueue, &n );
     543    if( trackerSupportsScrape( t ) )
     544    {
     545        char * uri;
    720546        struct evhttp_connection * evcon;
    721547        struct evhttp_request *req;
    722 
    723         ask_n = n;
    724         if( ask_n > t->multiscrapeMax )
    725             ask_n = t->multiscrapeMax;
    726 
    727         /**
    728         ***  Build the scrape request
    729         **/
    730 
    731         len = addr_len = strlen( address->scrape );
    732         for( i=0; i<ask_n; ++i )
    733             len += strlen("&info_hash=") + strlen(torrents[i]->escaped);
    734         ++len; /* for nul */
    735         uri = march = tr_new( char, len );
    736         memcpy( march, address->scrape, addr_len ); march += addr_len;
    737         for( i=0; i<ask_n; ++i ) {
    738             const int elen = strlen( torrents[i]->escaped );
    739             *march++ = i?'&':'?';
    740             memcpy( march, "info_hash=", 10); march += 10;
    741             memcpy( march, torrents[i]->escaped, elen ); march += elen;
    742         }
    743         *march++ = '\0';
    744         assert( march - uri == len );
    745 
    746         /* move the first n_ask torrents from scrapeQueue to scraping */
    747         for( i=0; i<ask_n; ++i )
    748             tr_ptrArrayInsertSorted( t->scraping, torrents[i], torrentCompare );
    749         tr_ptrArrayErase( t->scrapeQueue, 0, ask_n );
    750 
    751         /* ping the tracker */
     548        struct evbuffer * buf = evbuffer_new( );
     549
     550        evbuffer_add_printf( buf, "%s?info_hash=%s", address->scrape, t->escaped );
     551        uri = tr_strdup( (char*) EVBUFFER_DATA( buf ) );
     552        evbuffer_free( buf );
     553
    752554        tr_inf( "Sending scrape to tracker %s:%d: %s",
    753555                address->address, address->port, uri );
     556
    754557        evcon = getConnection( t, address->address, address->port );
    755558        evhttp_connection_set_timeout( evcon, TIMEOUT_INTERVAL_SEC );
    756         req = evhttp_request_new( onScrapeResponse, tr_strdup(t->primaryAddress) );
    757         assert( req );
     559        req = evhttp_request_new( onScrapeResponse, torrentHashNew( t ) );
    758560        addCommonHeaders( t, req );
    759561        tr_evhttp_make_request( t->handle, evcon, req, EVHTTP_REQ_GET, uri );
     
    762564    t->scrapeTimer = NULL;
    763565    return FALSE;
     566}
     567
     568static void
     569scrapeNow( tr_tracker * t )
     570{
     571    onScrapeNow( t );
    764572}
    765573
     
    770578***/
    771579
    772 static int
    773 torrentIsRunning( const Torrent * tor )
    774 {
    775     return tor && tor->isRunning;
    776 }
    777 
    778580static char*
    779 buildTrackerRequestURI( const Torrent     * tor,
     581buildTrackerRequestURI( const tr_tracker  * t,
    780582                        const tr_torrent  * torrent,
    781583                        const char        * eventName )
     
    783585    const int isStopping = !strcmp( eventName, "stopped" );
    784586    const int numwant = isStopping ? 0 : NUMWANT;
    785     char buf[4096];
    786 
    787     snprintf( buf, sizeof(buf), "%s"
    788                                 "?info_hash=%s"
    789                                 "&peer_id=%s"
    790                                 "&port=%d"
    791                                 "&uploaded=%"PRIu64
    792                                 "&downloaded=%"PRIu64
    793                                 "&corrupt=%"PRIu64
    794                                 "&left=%"PRIu64
    795                                 "&compact=1"
    796                                 "&numwant=%d"
    797                                 "&key=%s"
    798                                 "%s%s"
    799                                 "%s%s",
    800         getCurrentAddress(tor->tracker)->announce,
    801         tor->escaped,
    802         tor->peer_id,
    803         tr_sharedGetPublicPort( torrent->handle->shared ),
     587    struct evbuffer * buf = evbuffer_new( );
     588    char * ret;
     589
     590    evbuffer_add_printf( buf, "%s"
     591                              "?info_hash=%s"
     592                              "&peer_id=%s"
     593                              "&port=%d"
     594                              "&uploaded=%"PRIu64
     595                              "&downloaded=%"PRIu64
     596                              "&corrupt=%"PRIu64
     597                              "&left=%"PRIu64
     598                              "&compact=1"
     599                              "&numwant=%d"
     600                              "&key=%s"
     601                              "%s%s"
     602                              "%s%s",
     603        getCurrentAddress(t)->announce,
     604        t->escaped,
     605        t->peer_id,
     606        tr_sharedGetPublicPort( t->handle->shared ),
    804607        torrent->uploadedCur,
    805608        torrent->downloadedCur,
     
    807610        tr_cpLeftUntilComplete( torrent->completion ),
    808611        numwant,
    809         tor->tracker->key_param,
     612        t->key_param,
    810613        ( ( eventName && *eventName ) ? "&event=" : "" ),
    811614        ( ( eventName && *eventName ) ? eventName : "" ),
    812         ( ( tor->trackerID && *tor->trackerID ) ? "&trackerid=" : "" ),
    813         ( ( tor->trackerID && *tor->trackerID ) ? tor->trackerID : "" ) );
    814 
    815     return tr_strdup( buf );
     615        ( ( t->trackerID && *t->trackerID ) ? "&trackerid=" : "" ),
     616        ( ( t->trackerID && *t->trackerID ) ? t->trackerID : "" ) );
     617
     618    ret = tr_strdup( (char*) EVBUFFER_DATA( buf ) );
     619    evbuffer_free( buf );
     620    return ret;
    816621}
    817622
    818623/* Convert to compact form */
    819624static uint8_t *
    820 parseOldPeers( benc_val_t * bePeers, int * peerCount )
    821 {
    822     int i, count;
    823     uint8_t * compact;
     625parseOldPeers( benc_val_t * bePeers, int * setmePeerCount )
     626{
     627    int i;
     628    uint8_t *compact, *walk;
     629    const int peerCount = bePeers->val.l.count;
    824630
    825631    assert( bePeers->type == TYPE_LIST );
    826632
    827     compact = tr_new( uint8_t, 6 * bePeers->val.l.count );
    828 
    829     for( i=count=0; i<bePeers->val.l.count; ++i )
     633    compact = tr_new( uint8_t, peerCount*6 );
     634
     635    for( i=0, walk=compact; i<peerCount; ++i )
    830636    {
    831637        struct in_addr addr;
     
    838644            continue;
    839645
    840         memcpy( &compact[6 * count], &addr, 4 );
     646        memcpy( walk, &addr, 4 );
     647        walk += 4;
    841648
    842649        val = tr_bencDictFind( peer, "port" );
     
    845652
    846653        port = htons( val->val.i );
    847         memcpy( &compact[6 * count + 4], &port, 2 );
    848         ++count;
    849     }
    850 
    851     *peerCount = count;
     654        memcpy( walk, &port, 2 );
     655        walk += 2;
     656    }
     657
     658    *setmePeerCount = peerCount;
    852659    return compact;
    853660}
    854661
    855 /* handle braindead trackers whose minimums is higher
    856    than the interval. */
    857 static void
    858 setAnnounceInterval( Tracker  * t,
    859                      int        minimum,
    860                      int        interval )
    861 {
    862     assert( t != NULL );
    863 
    864     if( minimum > 0 )
    865         t->minAnnounceIntervalSec = minimum;
    866 
    867     if( interval > 0 )
    868         t->announceIntervalSec = interval;
    869 
    870     if( t->announceIntervalSec < t->minAnnounceIntervalSec )
    871         t->announceIntervalSec = t->minAnnounceIntervalSec;
    872 }
    873 
    874662static int onReannounceNow( void * vtor );
    875663
     
    879667}
    880668
    881 static int
    882 getManualReannounceIntervalSecs( const Tracker * tracker )
    883 {
    884     return tracker
    885         ? MAX( tracker->minAnnounceIntervalSec, DEFAULT_MANUAL_ANNOUNCE_INTERVAL_SEC )
    886         : DEFAULT_MANUAL_ANNOUNCE_INTERVAL_SEC;
    887 }
    888 
    889669static void
    890670onTrackerResponse( struct evhttp_request * req, void * torrent_hash )
    891671{
    892     char * errmsg;
    893     Torrent * tor;
    894     int isStopped;
    895     int reannounceIntervalSecs;
    896     tr_torrent * t;
    897 
    898     t = findTorrentFromHash( torrent_hash );
    899     tr_free( torrent_hash );
    900     if( t == NULL ) /* torrent has been closed */
     672    const char * warning;
     673    tr_tracker * t;
     674    int err = 0;
     675
     676    t = findTrackerFromHash( torrent_hash );
     677    if( t == NULL ) /* tracker has been closed */
    901678        return;
    902679
    903     tor = t->tracker;
    904     isStopped = !torrentIsRunning( tor );
    905 
    906680    tr_inf( "Torrent \"%s\" tracker response: %s",
    907             tor->name,
     681            t->name,
    908682            ( req ? req->response_code_line : "(null)") );
    909683
     
    913687        const int bencLoaded = !parseBencResponse( req, &benc );
    914688
    915         publishErrorClear( tor );
     689        publishErrorClear( t );
    916690
    917691        if( bencLoaded && benc.type==TYPE_DICT )
     
    920694
    921695            if(( tmp = tr_bencDictFind( &benc, "failure reason" )))
    922                 publishErrorMessage( tor, tmp->val.s.s );
     696                publishErrorMessage( t, tmp->val.s.s );
    923697
    924698            if(( tmp = tr_bencDictFind( &benc, "warning message" )))
    925                 publishWarningMessage( tor, tmp->val.s.s );
     699                publishWarning( t, tmp->val.s.s );
    926700
    927701            if(( tmp = tr_bencDictFind( &benc, "interval" )))
    928                 setAnnounceInterval( tor->tracker, -1, tmp->val.i * 1000 );
     702                t->announceIntervalSec = tmp->val.i;
    929703
    930704            if(( tmp = tr_bencDictFind( &benc, "min interval" )))
    931                 setAnnounceInterval( tor->tracker, tmp->val.i * 1000, -1 );
     705                t->announceMinIntervalSec = tmp->val.i;
    932706
    933707            if(( tmp = tr_bencDictFind( &benc, "tracker id" )))
    934                 tor->trackerID = tr_strndup( tmp->val.s.s, tmp->val.s.i );
     708                t->trackerID = tr_strndup( tmp->val.s.s, tmp->val.s.i );
    935709
    936710            if(( tmp = tr_bencDictFind( &benc, "complete" )))
    937                 tor->seeders = tmp->val.i;
     711                t->seederCount = tmp->val.i;
    938712
    939713            if(( tmp = tr_bencDictFind( &benc, "incomplete" )))
    940                 tor->leechers = tmp->val.i;
     714                t->leecherCount = tmp->val.i;
    941715
    942716            if(( tmp = tr_bencDictFind( &benc, "peers" )))
     
    960734                }
    961735
    962                 publishNewPeers( tor, peerCount, peerCompact );
     736                publishNewPeers( t, peerCount, peerCompact );
    963737                tr_free( peerCompact );
    964738            }
    965739        }
    966740
    967         reannounceIntervalSecs = isStopped
    968             ? -1
    969             : tor->tracker->announceIntervalSec;
    970 
    971741        if( bencLoaded )
    972742            tr_bencFree( &benc );
     
    974744    else
    975745    {
    976         tr_inf( "Bad response from tracker '%s' on request '%s' "
    977                 "for torrent '%s'... trying again in 30 seconds",
    978                 tor->tracker->primaryAddress,
    979                 tor->lastRequest,
    980                 tor->name );
    981 
    982         reannounceIntervalSecs = 30;
    983     }
    984 
    985     if (( errmsg = updateAddresses( tor->tracker, req ) )) {
    986         publishErrorMessage( tor, errmsg );
    987         tr_err( errmsg );
    988         tr_free( errmsg );
    989     }
    990 
    991     if( !isStopped && reannounceIntervalSecs>0 ) {
     746        tr_inf( "Bad response for torrent '%s' on request '%s' "
     747                "... trying again in 30 seconds",
     748                t->name, t->lastRequest );
     749
     750        err = 1;
     751    }
     752
     753    if (( warning = updateAddresses( t, req ) )) {
     754        publishWarning( t, warning );
     755        tr_err( warning );
     756    }
     757
     758    /* set reannounce times */
     759    tr_timerFree( &t->reannounceTimer );
     760    t->reannounceTimer = NULL;
     761    t->manualAnnounceAllowedAt = ~(time_t)0;
     762    if( t->isRunning )
     763    {
    992764        tr_dbg( "torrent '%s' reannouncing in %d seconds",
    993                 tor->name, (reannounceIntervalSecs) );
    994         tr_timerFree( &tor->reannounceTimer );
    995         tor->reannounceTimer = tr_timerNew( tor->tracker->handle, onReannounceNow, tor, reannounceIntervalSecs*1000 );
    996         tor->manualAnnounceAllowedAt = time(NULL) + getManualReannounceIntervalSecs( tor->tracker );
     765                t->name, t->announceIntervalSec );
     766
     767        t->reannounceTimer = tr_timerNew( t->handle,
     768                                          onReannounceNow, t,
     769                                          t->announceIntervalSec * 1000 );
     770
     771        t->manualAnnounceAllowedAt = time(NULL) + t->announceMinIntervalSec;
    997772    }
    998773}
     
    1001776sendTrackerRequest( void * vt, const char * eventName )
    1002777{
    1003     Torrent * t = (Torrent *) vt;
     778    tr_tracker * t = vt;
    1004779    const int isStopping = eventName && !strcmp( eventName, "stopped" );
    1005     const tr_tracker_info * address = getCurrentAddress( t->tracker );
     780    const tr_tracker_info * address = getCurrentAddress( t );
    1006781    char * uri;
    1007782    struct evhttp_connection * evcon;
    1008783    const tr_torrent * tor;
    1009784
    1010     tor = tr_torrentFindFromHash( t->tracker->handle, t->hash );
     785    tor = tr_torrentFindFromHash( t->handle, t->hash );
    1011786    if( tor == NULL )
    1012787        return FALSE;   
     
    1023798    tr_timerFree( &t->reannounceTimer );
    1024799
    1025     evcon = getConnection( t->tracker, address->address, address->port );
     800    evcon = getConnection( t, address->address, address->port );
    1026801    if ( !evcon ) {
    1027802        tr_err( "Can't make a connection to %s:%d", address->address, address->port );
    1028803        tr_free( uri );
    1029804    } else {
    1030         struct evhttp_request * httpReq;
     805        struct evhttp_request * req;
    1031806        tr_free( t->lastRequest );
    1032807        t->lastRequest = tr_strdup( eventName );
    1033808        if( isStopping ) {
    1034             evhttp_connection_set_timeout( evcon, STOPPING_TIMEOUT_INTERVAL_SEC );
    1035             httpReq = evhttp_request_new( onStoppedResponse, t->tracker->handle );
     809            evhttp_connection_set_timeout( evcon, STOP_TIMEOUT_INTERVAL_SEC );
     810            req = evhttp_request_new( onStoppedResponse, t->handle );
    1036811        } else {
    1037812            evhttp_connection_set_timeout( evcon, TIMEOUT_INTERVAL_SEC );
    1038             httpReq = evhttp_request_new( onTrackerResponse, torrentHashNew(t) );
     813            req = evhttp_request_new( onTrackerResponse, torrentHashNew(t) );
    1039814        }
    1040         addCommonHeaders( t->tracker, httpReq );
    1041         tr_evhttp_make_request( t->tracker->handle, evcon,
    1042                                 httpReq, EVHTTP_REQ_GET, uri );
     815        addCommonHeaders( t, req );
     816        tr_evhttp_make_request( t->handle, evcon,
     817                                req, EVHTTP_REQ_GET, uri );
    1043818    }
    1044819
     
    1047822
    1048823static int
    1049 onReannounceNow( void * vtor )
    1050 {
    1051     Torrent * tor = (Torrent *) vtor;
    1052     sendTrackerRequest( tor, "" );
    1053     tor->reannounceTimer = NULL;
     824onReannounceNow( void * vt )
     825{
     826    tr_tracker * t = vt;
     827    sendTrackerRequest( t, "" );
     828    t->reannounceTimer = NULL;
    1054829    return FALSE;
    1055830}
     
    1060835
    1061836tr_publisher_tag
    1062 tr_trackerSubscribe( Torrent             * tor,
     837tr_trackerSubscribe( tr_tracker          * t,
    1063838                     tr_delivery_func      func,
    1064839                     void                * user_data )
    1065840{
    1066     return tr_publisherSubscribe( tor->publisher, func, user_data );
     841    return tr_publisherSubscribe( t->publisher, func, user_data );
    1067842}
    1068843
    1069844void
    1070 tr_trackerUnsubscribe( Torrent           * tor,
     845tr_trackerUnsubscribe( tr_tracker        * t,
    1071846                       tr_publisher_tag    tag )
    1072847{
    1073     tr_publisherUnsubscribe( tor->publisher, tag );
     848    tr_publisherUnsubscribe( t->publisher, tag );
    1074849}
    1075850
    1076851const tr_tracker_info *
    1077 tr_trackerGetAddress( const Torrent * tor )
    1078 {
    1079     return getCurrentAddress( tor->tracker );
     852tr_trackerGetAddress( const tr_tracker   * t )
     853{
     854    return getCurrentAddress( t );
    1080855}
    1081856
    1082857int
    1083 tr_trackerCanManualAnnounce ( const Torrent * tor )
    1084 {
    1085     /* return true if this torrent's currently running
    1086        and it's been long enough since the last announce */
    1087     return ( torrentIsRunning( tor ) )
    1088         && ( time(NULL) >= tor->manualAnnounceAllowedAt );
     858tr_trackerCanManualAnnounce ( const tr_tracker * t)
     859{
     860    return t->isRunning
     861            && ( time(NULL) >= t->manualAnnounceAllowedAt );
    1089862}
    1090863
    1091864void
    1092 tr_trackerGetCounts( const Torrent       * tor,
    1093                      int                 * setme_completedCount,
    1094                      int                 * setme_leecherCount,
    1095                      int                 * setme_seederCount )
     865tr_trackerGetCounts( const tr_tracker  * t,
     866                     int               * setme_completedCount,
     867                     int               * setme_leecherCount,
     868                     int               * setme_seederCount )
    1096869{
    1097870    if( setme_completedCount )
    1098        *setme_completedCount = tor->timesDownloaded;
     871       *setme_completedCount = t->timesDownloaded;
    1099872
    1100873    if( setme_leecherCount )
    1101        *setme_leecherCount = tor->leechers;
     874       *setme_leecherCount = t->leecherCount;
    1102875
    1103876    if( setme_seederCount )
    1104        *setme_seederCount = tor->seeders;
     877       *setme_seederCount = t->seederCount;
    1105878}
    1106879
    1107880void
    1108 tr_trackerStart( Torrent * tor )
    1109 {
    1110     tr_peerIdNew( tor->peer_id, sizeof(tor->peer_id) );
    1111 
    1112     if( !tor->reannounceTimer && !tor->isRunning )
    1113     {
    1114         tor->isRunning = 1;
    1115         sendTrackerRequest( tor, "started" );
     881tr_trackerStart( tr_tracker * t )
     882{
     883    tr_peerIdNew( t->peer_id, sizeof(t->peer_id) );
     884
     885    if( !t->reannounceTimer && !t->isRunning )
     886    {
     887        t->isRunning = 1;
     888        sendTrackerRequest( t, "started" );
    1116889    }
    1117890}
    1118891
    1119892void
    1120 tr_trackerReannounce( Torrent * tor )
    1121 {
    1122     sendTrackerRequest( tor, "started" );
     893tr_trackerReannounce( tr_tracker * t )
     894{
     895    sendTrackerRequest( t, "started" );
    1123896}
    1124897
    1125898void
    1126 tr_trackerCompleted( Torrent * tor )
    1127 {
    1128     sendTrackerRequest( tor, "completed" );
     899tr_trackerCompleted( tr_tracker * t )
     900{
     901    sendTrackerRequest( t, "completed" );
    1129902}
    1130903
    1131904void
    1132 tr_trackerStop( Torrent * tor )
    1133 {
    1134     if( tor->isRunning )
    1135     {
    1136         tor->isRunning = 0;
    1137         sendTrackerRequest( tor, "stopped" );
     905tr_trackerStop( tr_tracker * t )
     906{
     907    if( t->isRunning )
     908    {
     909        t->isRunning = 0;
     910        sendTrackerRequest( t, "stopped" );
    1138911    }
    1139912}
    1140913
    1141914void
    1142 tr_trackerChangeMyPort( Torrent * tor )
    1143 {
    1144     if( torrentIsRunning( tor ) )
    1145         tr_trackerReannounce( tor );
    1146 }
     915tr_trackerChangeMyPort( tr_tracker * t )
     916{
     917    if( t->isRunning )
     918        tr_trackerReannounce( t );
     919}
  • trunk/libtransmission/tracker.h

    r3284 r3451  
    2222**/
    2323
    24 struct tr_tracker * tr_trackerNew( tr_torrent * );
     24typedef struct tr_tracker tr_tracker;
    2525
    26 void  tr_trackerFree ( struct tr_tracker * );
     26tr_tracker * tr_trackerNew( const tr_torrent * );
     27
     28void  tr_trackerFree ( tr_tracker * );
    2729
    2830/**
     
    5456    int peerCount;
    5557}
    56 tr_tracker_event_t;
     58tr_tracker_event;
    5759
    5860tr_publisher_tag  tr_trackerSubscribe       ( struct tr_tracker * tag,
Note: See TracChangeset for help on using the changeset viewer.