#include "announcer.h"
#include "announcer-common.h"
#include "crypto.h"
-#include "net.h"
#include "peer-mgr.h" /* tr_peerMgrCompactToPex() */
#include "ptrarray.h"
#include "session.h"
#include "tr-lpd.h"
#include "torrent.h"
#include "utils.h"
-#include "web.h"
struct tr_tier;
*/
typedef struct tr_announcer
{
- /* Since we can't poll a tr_torrent's fields after it's destroyed,
- * we pre-build the "stop" tr_announce_request when a torrent is
- * removed from Transmission */
- tr_ptrArray stops;
+ tr_ptrArray stops; /* tr_announce_request */
tr_session * session;
struct event * upkeepTimer;
}
static inline time_t
-valPlusJitter( const int minPeriod )
+jitterize( const int val )
{
const double jitter = 0.1;
-
- assert( minPeriod > 0 );
-
- return tr_time()
- + minPeriod
- + tr_cryptoWeakRandInt( (int) ( minPeriod * jitter ) + 1 );
+ assert( val > 0 );
+ return val + tr_cryptoWeakRandInt((int)(1 + val * jitter));
}
static void
{
tr_announcer * a;
- const time_t lpdAt = valPlusJitter( LPD_HOUSEKEEPING_INTERVAL_SECS / 3 );
-
assert( tr_isSession( session ) );
a = tr_new0( tr_announcer, 1 );
a->key = tr_cryptoRandInt( INT_MAX );
a->session = session;
a->slotsAvailable = MAX_CONCURRENT_TASKS;
- a->lpdUpkeepAt = lpdAt;
+ a->lpdUpkeepAt = tr_time() + jitterize(5);
a->upkeepTimer = evtimer_new( session->event_base, onUpkeepTimer, a );
tr_timerAdd( a->upkeepTimer, UPKEEP_INTERVAL_SECS, 0 );
/* a row in tr_tier's list of trackers */
typedef struct
{
- char * hostname;
+ char * key;
char * announce;
char * scrape;
}
tr_tracker;
-/* format: hostname + ':' + port */
+/* format: host+':'+ port */
static char *
-getHostName( const char * url )
+getKey( const char * url )
{
int port = 0;
char * host = NULL;
trackerNew( const char * announce, const char * scrape, uint32_t id )
{
tr_tracker * tracker = tr_new0( tr_tracker, 1 );
- tracker->hostname = getHostName( announce );
+ tracker->key = getKey( announce );
tracker->announce = tr_strdup( announce );
tracker->scrape = tr_strdup( scrape );
tracker->id = id;
tr_free( tracker->tracker_id_str );
tr_free( tracker->scrape );
tr_free( tracker->announce );
- tr_free( tracker->hostname );
+ tr_free( tracker->key );
tr_free( tracker );
}
{
tr_snprintf( buf, buflen, "[%s---%s]",
( tier && tier->tor ) ? tr_torrentName( tier->tor ) : "?",
- ( tier && tier->currentTracker ) ? tier->currentTracker->hostname : "?" );
+ ( tier && tier->currentTracker ) ? tier->currentTracker->key : "?" );
}
static void
static void
publishMessage( tr_tier * tier, const char * msg, int type )
{
- if( tier && tier->tor && tier->tor->tiers )
+ if( tier && tier->tor && tier->tor->tiers && tier->tor->tiers->callback )
{
tr_torrent_tiers * tiers = tier->tor->tiers;
tr_tracker_event event = TRACKER_EVENT_INIT;
if( tier->currentTracker )
event.tracker = tier->currentTracker->announce;
- if( tiers->callback != NULL )
- tiers->callback( tier->tor, &event, tiers->callbackData );
+ tiers->callback( tier->tor, &event, tiers->callbackData );
}
}
publishPeersPex( tr_tier * tier, int seeds, int leechers,
const tr_pex * pex, int n )
{
- tr_tracker_event e = TRACKER_EVENT_INIT;
- e.messageType = TR_TRACKER_PEERS;
- e.seedProbability = getSeedProbability( tier, seeds, leechers, n );
- e.pex = pex;
- e.pexCount = n;
-
- dbgmsg( tier, "got %d peers; seed probability %d", n, (int)e.seedProbability );
+ if( tier->tor->tiers->callback )
+ {
+ tr_tracker_event e = TRACKER_EVENT_INIT;
+ e.messageType = TR_TRACKER_PEERS;
+ e.seedProbability = getSeedProbability( tier, seeds, leechers, n );
+ e.pex = pex;
+ e.pexCount = n;
+ dbgmsg( tier, "got %d peers; seed prob %d", n, (int)e.seedProbability );
- if( tier->tor->tiers->callback != NULL )
tier->tor->tiers->callback( tier->tor, &e, NULL );
+ }
}
/***
if( !tor->isRunning )
return FALSE;
+ /* return true if any tier can manual announce */
n = tr_ptrArraySize( &tor->tiers->tiers );
tiers = (const tr_tier**) tr_ptrArrayBase( &tor->tiers->tiers );
for( i=0; i<n; ++i )
assert( tr_isTorrent( tor ) );
+ /* find the earliest manual announce time from all peers */
tiers = tor->tiers;
n = tr_ptrArraySize( &tiers->tiers );
for( i=0; i<n; ++i ) {
static void
tier_announce_remove_trailing( tr_tier * tier, tr_announce_event e )
{
- while( ( tier->announce_event_count > 0 ) && ( tier->announce_events[tier->announce_event_count-1] == e ) )
+ while( ( tier->announce_event_count > 0 )
+ && ( tier->announce_events[tier->announce_event_count-1] == e ) )
--tier->announce_event_count;
}
static void
-tier_announce_event_push( tr_tier * tier, tr_announce_event e, time_t announceAt )
+tier_announce_event_push( tr_tier * tier,
+ tr_announce_event e,
+ time_t announceAt )
{
int i;
assert( tier != NULL );
dbgmsg_tier_announce_queue( tier );
- dbgmsg( tier, "appending \"%s\" to announce queue", tr_announce_event_get_string( e ) );
+ dbgmsg( tier, "queued \"%s\"", tr_announce_event_get_string( e ) );
if( tier->announce_event_count > 0 )
{
assert( tr_isTorrent( tor ) );
+ /* walk through each tier and tell them to announce */
tiers = tor->tiers;
n = tr_ptrArraySize( &tiers->tiers );
for( i=0; i<n; ++i )
if(( str = response->warning ))
{
- tr_strlcpy( tier->lastAnnounceStr, str, sizeof( tier->lastAnnounceStr ) );
+ tr_strlcpy( tier->lastAnnounceStr, str,
+ sizeof( tier->lastAnnounceStr ) );
dbgmsg( tier, "tracker gave \"%s\"", str );
publishWarning( tier, str );
}
find_tier( tr_torrent * tor, const char * url )
{
int i;
- int n = tr_ptrArraySize( &tor->tiers->tiers );
+ const int n = tr_ptrArraySize( &tor->tiers->tiers );
tr_tier ** tiers = (tr_tier**) tr_ptrArrayBase( &tor->tiers->tiers );
for( i=0; i<n; ++i ) {
static void
announceMore( tr_announcer * announcer )
{
- tr_torrent * tor = NULL;
+ int i;
+ int n;
+ tr_torrent * tor;
+ tr_ptrArray announceMe = TR_PTR_ARRAY_INIT;
+ tr_ptrArray scrapeMe = TR_PTR_ARRAY_INIT;
const time_t now = tr_time( );
dbgmsg( NULL, "announceMore: slotsAvailable is %d", announcer->slotsAvailable );
- if( announcer->slotsAvailable > 0 )
- {
- int i;
- int n;
- tr_ptrArray announceMe = TR_PTR_ARRAY_INIT;
- tr_ptrArray scrapeMe = TR_PTR_ARRAY_INIT;
-
- /* build a list of tiers that need to be announced */
- while(( tor = tr_torrentNext( announcer->session, tor ))) {
- if( tor->tiers ) {
- n = tr_ptrArraySize( &tor->tiers->tiers );
- for( i=0; i<n; ++i ) {
- tr_tier * tier = tr_ptrArrayNth( &tor->tiers->tiers, i );
- if( tierNeedsToAnnounce( tier, now ) )
- tr_ptrArrayAppend( &announceMe, tier );
- else if( tierNeedsToScrape( tier, now ) )
- tr_ptrArrayAppend( &scrapeMe, tier );
- }
+ if( announcer->slotsAvailable < 1 )
+ return;
+
+ /* build a list of tiers that need to be announced */
+ tor = NULL;
+ while(( tor = tr_torrentNext( announcer->session, tor ))) {
+ if( tor->tiers ) {
+ n = tr_ptrArraySize( &tor->tiers->tiers );
+ for( i=0; i<n; ++i ) {
+ tr_tier * tier = tr_ptrArrayNth( &tor->tiers->tiers, i );
+ if( tierNeedsToAnnounce( tier, now ) )
+ tr_ptrArrayAppend( &announceMe, tier );
+ else if( tierNeedsToScrape( tier, now ) )
+ tr_ptrArrayAppend( &scrapeMe, tier );
}
}
+ }
- /* if there are more tiers than slots available, prioritize */
- n = tr_ptrArraySize( &announceMe );
- if( n > announcer->slotsAvailable )
- qsort( tr_ptrArrayBase( &announceMe ), n, sizeof( tr_tier * ), compareTiers );
+ /* if there are more tiers than slots available, prioritize */
+ n = tr_ptrArraySize( &announceMe );
+ if( n > announcer->slotsAvailable )
+ qsort( tr_ptrArrayBase(&announceMe), n, sizeof(tr_tier*), compareTiers );
- /* announce some */
- n = MIN( tr_ptrArraySize( &announceMe ), announcer->slotsAvailable );
- for( i=0; i<n; ++i ) {
- tr_tier * tier = tr_ptrArrayNth( &announceMe, i );
- dbgmsg( tier, "announcing tier %d of %d", i, n );
- tierAnnounce( announcer, tier );
- }
+ /* announce some */
+ n = MIN( tr_ptrArraySize( &announceMe ), announcer->slotsAvailable );
+ for( i=0; i<n; ++i ) {
+ tr_tier * tier = tr_ptrArrayNth( &announceMe, i );
+ dbgmsg( tier, "announcing tier %d of %d", i, n );
+ tierAnnounce( announcer, tier );
+ }
- /* scrape some */
- multiscrape( announcer, &scrapeMe );
+ /* scrape some */
+ multiscrape( announcer, &scrapeMe );
-#if 0
-char timebuf[64];
-tr_getLogTimeStr( timebuf, 64 );
-fprintf( stderr, "[%s] announce.c has %d requests ready to send (announce: %d, scrape: %d)\n", timebuf, (int)(tr_ptrArraySize(&announceMe)+tr_ptrArraySize(&scrapeMe)), (int)tr_ptrArraySize(&announceMe), (int)tr_ptrArraySize(&scrapeMe) );
-#endif
+ /* cleanup */
+ tr_ptrArrayDestruct( &scrapeMe, NULL );
+ tr_ptrArrayDestruct( &announceMe, NULL );
+}
- /* cleanup */
- tr_ptrArrayDestruct( &scrapeMe, NULL );
- tr_ptrArrayDestruct( &announceMe, NULL );
- }
+static void
+dht_upkeep( tr_session * session )
+{
+ tr_torrent * tor = NULL;
+ const time_t now = tr_time( );
- tor = NULL;
- while(( tor = tr_torrentNext( announcer->session, tor ))) {
- if( tor->dhtAnnounceAt <= now ) {
+ while(( tor = tr_torrentNext( session, tor )))
+ {
+ if( tor->dhtAnnounceAt <= now )
+ {
if( tor->isRunning && tr_torrentAllowsDHT(tor) ) {
- int rc;
- rc = tr_dhtAnnounce(tor, AF_INET, 1);
+ const int rc = tr_dhtAnnounce(tor, AF_INET, 1);
if(rc == 0)
/* The DHT is not ready yet. Try again soon. */
tor->dhtAnnounceAt = now + 5 + tr_cryptoWeakRandInt( 5 );
}
}
- if( tor->dhtAnnounce6At <= now ) {
+ if( tor->dhtAnnounce6At <= now )
+ {
if( tor->isRunning && tr_torrentAllowsDHT(tor) ) {
- int rc;
- rc = tr_dhtAnnounce(tor, AF_INET6, 1);
+ const int rc = tr_dhtAnnounce(tor, AF_INET6, 1);
if(rc == 0)
tor->dhtAnnounce6At = now + 5 + tr_cryptoWeakRandInt( 5 );
else
/* maybe send out some announcements to trackers */
announceMore( announcer );
+ dht_upkeep( announcer->session );
+
/* LPD upkeep */
if( announcer->lpdUpkeepAt <= now ) {
const int seconds = LPD_HOUSEKEEPING_INTERVAL_SECS;
- announcer->lpdUpkeepAt = valPlusJitter( seconds );
+ announcer->lpdUpkeepAt = now + jitterize( seconds );
tr_lpdAnnounceMore( now, seconds );
}
***/
tr_tracker_stat *
-tr_announcerStats( const tr_torrent * torrent,
- int * setmeTrackerCount )
+tr_announcerStats( const tr_torrent * torrent, int * setmeTrackerCount )
{
int i;
int n;
tr_tracker_stat * st = ret + out++;
st->id = tracker->id;
- tr_strlcpy( st->host, tracker->hostname, sizeof( st->host ) );
+ tr_strlcpy( st->host, tracker->key, sizeof( st->host ) );
tr_strlcpy( st->announce, tracker->announce, sizeof( st->announce ) );
st->tier = i;
st->isBackup = tracker != tier->currentTracker;
st->lastScrapeTime = tier->lastScrapeTime;
st->lastScrapeSucceeded = tier->lastScrapeSucceeded;
st->lastScrapeTimedOut = tier->lastScrapeTimedOut;
- tr_strlcpy( st->lastScrapeResult, tier->lastScrapeStr, sizeof( st->lastScrapeResult ) );
+ tr_strlcpy( st->lastScrapeResult, tier->lastScrapeStr,
+ sizeof( st->lastScrapeResult ) );
}
if( tier->isScraping )
if(( st->hasAnnounced = tier->lastAnnounceTime != 0 )) {
st->lastAnnounceTime = tier->lastAnnounceTime;
- tr_strlcpy( st->lastAnnounceResult, tier->lastAnnounceStr, sizeof( st->lastAnnounceResult ) );
+ tr_strlcpy( st->lastAnnounceResult, tier->lastAnnounceStr,
+ sizeof( st->lastAnnounceResult ) );
st->lastAnnounceSucceeded = tier->lastAnnounceSucceeded;
st->lastAnnounceTimedOut = tier->lastAnnounceTimedOut;
st->lastAnnouncePeerCount = tier->lastAnnouncePeerCount;