(libT) #1379: support "partial seeds" BEP 22

This commit is contained in:
Charles Kerr 2008-12-02 19:46:51 +00:00
parent 341b40f192
commit d4ee0d714a
9 changed files with 105 additions and 35 deletions

View File

@ -48,6 +48,7 @@ typedef enum
TR_PEER_PEER_PROGRESS,
TR_PEER_ERROR,
TR_PEER_CANCEL,
TR_PEER_UPLOAD_ONLY,
TR_PEER_NEED_REQ
}
PeerEventType;
@ -61,6 +62,7 @@ typedef struct
float progress; /* for PEER_PROGRESS */
int err; /* errno for GOT_ERROR */
int wasPieceData; /* for GOT_DATA */
tr_bool uploadOnly; /* for UPLOAD_ONLY */
}
tr_peer_event;

View File

@ -89,6 +89,13 @@ enum
***
**/
enum
{
UPLOAD_ONLY_UKNOWN,
UPLOAD_ONLY_YES,
UPLOAD_ONLY_NO
};
/* We keep one of these for every peer we know about, whether
* it's connected or not, so the struct must be small.
* When our current connections underperform, we dip back
@ -96,12 +103,14 @@ enum
struct peer_atom
{
uint8_t from;
uint8_t flags; /* these match the added_f flags */
uint8_t myflags; /* flags that aren't defined in added_f */
uint8_t flags; /* these match the added_f flags */
uint8_t myflags; /* flags that aren't defined in added_f */
uint8_t uploadOnly; /* UPLOAD_ONLY_ */
uint8_t partialSeed;
tr_port port;
uint16_t numFails;
tr_address addr;
time_t time; /* when the peer's connection status last changed */
time_t time; /* when the peer's connection status last changed */
time_t piece_data_time;
};
@ -980,6 +989,14 @@ peerCallbackFunc( void * vpeer,
switch( e->eventType )
{
case TR_PEER_UPLOAD_ONLY:
/* update our atom */
if( peer ) {
struct peer_atom * a = getExistingAtom( t, &peer->addr );
a->uploadOnly = e->uploadOnly ? UPLOAD_ONLY_YES : UPLOAD_ONLY_NO;
}
break;
case TR_PEER_NEED_REQ:
refillSoon( t );
break;
@ -1458,11 +1475,15 @@ tr_peerMgrGetPeers( tr_peerMgr * manager,
for( i = 0; i < peerCount; ++i, ++walk )
{
const tr_peer * peer = peers[i];
const struct peer_atom * atom = getExistingAtom( t, &peer->addr );
walk->addr = peer->addr;
walk->port = peer->port;
walk->flags = 0;
if( peerPrefersCrypto( peer ) ) walk->flags |= ADDED_F_ENCRYPTION_FLAG;
if( peer->progress >= 1.0 ) walk->flags |= ADDED_F_SEED_FLAG;
if( peerPrefersCrypto( peer ) )
walk->flags |= ADDED_F_ENCRYPTION_FLAG;
if( ( atom->uploadOnly == UPLOAD_ONLY_YES ) || ( peer->progress >= 1.0 ) )
walk->flags |= ADDED_F_SEED_FLAG;
}
assert( ( walk - pex ) == peerCount );
@ -1884,11 +1905,22 @@ rechoke( Torrent * t )
for( i = 0, size = 0; i < peerCount; ++i )
{
tr_peer * peer = peers[i];
struct peer_atom * atom = getExistingAtom( t, &peer->addr );
if( peer->progress >= 1.0 ) /* choke all seeds */
{
tr_peerMsgsSetChoke( peer->msgs, TRUE );
else if( chokeAll )
}
else if( atom->uploadOnly == UPLOAD_ONLY_YES ) /* choke partial seeds */
{
tr_peerMsgsSetChoke( peer->msgs, TRUE );
else {
}
else if( chokeAll ) /* choke everyone if we're not uploading */
{
tr_peerMsgsSetChoke( peer->msgs, TRUE );
}
else
{
struct ChokeData * n = &choke[size++];
n->peer = peer;
n->isInterested = peer->peerIsInterested;
@ -2175,7 +2207,8 @@ getPeerCandidates( Torrent * t,
continue;
/* no need to connect if we're both seeds... */
if( seed && ( atom->flags & ADDED_F_SEED_FLAG ) )
if( seed && ( ( atom->flags & ADDED_F_SEED_FLAG ) ||
( atom->uploadOnly == UPLOAD_ONLY_YES ) ) )
continue;
/* don't reconnect too often */

View File

@ -513,7 +513,7 @@ protocolSendHaveNone( tr_peermsgs * msgs )
*** EVENTS
**/
static const tr_peer_event blankEvent = { 0, 0, 0, 0, 0.0f, 0, 0 };
static const tr_peer_event blankEvent = { 0, 0, 0, 0, 0.0f, 0, 0, 0 };
static void
publish( tr_peermsgs * msgs,
@ -536,11 +536,19 @@ fireError( tr_peermsgs * msgs,
publish( msgs, &e );
}
static void
fireUploadOnly( tr_peermsgs * msgs, tr_bool uploadOnly )
{
tr_peer_event e = blankEvent;
e.eventType = TR_PEER_UPLOAD_ONLY;
e.uploadOnly = uploadOnly;
publish( msgs, &e );
}
static void
fireNeedReq( tr_peermsgs * msgs )
{
tr_peer_event e = blankEvent;
e.eventType = TR_PEER_NEED_REQ;
publish( msgs, &e );
}
@ -1086,9 +1094,9 @@ sendLtepHandshake( tr_peermsgs * msgs )
pex = 1;
tr_bencInitDict( &val, 4 );
tr_bencDictAddInt( &val, "e",
msgs->session->encryptionMode != TR_CLEAR_PREFERRED );
tr_bencDictAddInt( &val, "e", msgs->session->encryptionMode != TR_CLEAR_PREFERRED );
tr_bencDictAddInt( &val, "p", tr_sessionGetPeerPort( msgs->session ) );
tr_bencDictAddInt( &val, "upload_only", tr_torrentIsSeed( msgs->torrent ) );
tr_bencDictAddStr( &val, "v", TR_NAME " " USERAGENT_PREFIX );
m = tr_bencDictAddDict( &val, "m", 1 );
if( pex )
@ -1145,6 +1153,10 @@ parseLtepHandshake( tr_peermsgs * msgs,
}
}
/* look for upload_only (BEP 21) */
if( tr_bencDictFindInt( &val, "upload_only", &i ) )
fireUploadOnly( msgs, i!=0 );
/* get peer's listening port */
if( tr_bencDictFindInt( &val, "p", &i ) )
{

View File

@ -291,6 +291,8 @@ addField( const tr_torrent * tor,
tr_bencDictAddInt( d, key, st->doneDate );
else if( !strcmp( key, "downloadedEver" ) )
tr_bencDictAddInt( d, key, st->downloadedEver );
else if( !strcmp( key, "downloaders" ) )
tr_bencDictAddInt( d, key, st->downloaders );
else if( !strcmp( key, "downloadLimitMode" ) )
tr_bencDictAddInt( d, key, tr_torrentGetSpeedMode( tor, TR_DOWN ) );
else if( !strcmp( key, "downloadLimit" ) )

View File

@ -783,9 +783,12 @@ tr_torrentStat( tr_torrent * tor )
s->announceURL = ti ? ti->announce : NULL;
s->scrapeURL = ti ? ti->scrape : NULL;
tr_trackerStat( tc, s );
tr_trackerGetCounts( tc, &s->timesCompleted,
&s->leechers,
&s->seeders );
&s->leechers,
&s->seeders,
&s->downloaders );
tr_peerMgrTorrentStats( tor->session->peerMgr,
tor->info.hash,
&s->peersKnown,

View File

@ -108,6 +108,7 @@ struct tr_tracker
/* these are set from the latest tracker response... -1 is 'unknown' */
int timesDownloaded;
int seederCount;
int downloaderCount;
int leecherCount;
char * trackerID;
@ -538,7 +539,7 @@ onScrapeResponse( tr_session * session,
long responseCode,
const void * response,
size_t responseLen,
void * torrent_hash )
void * torrent_hash )
{
int success = FALSE;
int retry;
@ -583,9 +584,11 @@ onScrapeResponse( tr_session * session,
if( ( tr_bencDictFindInt( tordict, "downloaded", &itmp ) ) )
t->timesDownloaded = itmp;
if( ( tr_bencDictFindInt( tordict, "downloaders", &itmp ) ) )
t->downloaderCount = itmp;
if( tr_bencDictFindDict( tordict, "flags", &flags ) )
if( ( tr_bencDictFindInt( flags, "min_request_interval",
&itmp ) ) )
if( ( tr_bencDictFindInt( flags, "min_request_interval", &itmp ) ) )
t->scrapeIntervalSec = i;
/* as per ticket #1045, safeguard against trackers returning
@ -651,9 +654,9 @@ enum
TR_REQ_STARTED,
TR_REQ_COMPLETED,
TR_REQ_STOPPED,
TR_REQ_PAUSED, /* BEP 21 */
TR_REQ_REANNOUNCE,
TR_REQ_SCRAPE,
TR_REQ_COUNT
TR_REQ_SCRAPE
};
struct tr_tracker_request
@ -712,19 +715,23 @@ buildTrackerRequestURI( tr_tracker * t,
}
static struct tr_tracker_request*
createRequest( tr_session * session,
tr_tracker * tracker,
int reqtype )
createRequest( tr_session * session,
tr_tracker * tracker,
int reqtype )
{
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;
static const char* strings[] = { "started", "completed", "stopped", "paused", "", "err" };
const tr_torrent * torrent = tr_torrentFindFromHash( session, tracker->hash );
const tr_tracker_info * address = getCurrentAddressFromTorrent( tracker, torrent );
int isStopping;
struct tr_tracker_request * req;
struct evbuffer * url;
struct evbuffer * url;
/* BEP 21: In order to tell the tracker that a peer is a partial seed, it MUST send
* an event=paused parameter in every announce while it is a partial seed. */
if( tr_cpGetStatus( torrent->completion ) == TR_PARTIAL_SEED )
reqtype = TR_REQ_PAUSED;
isStopping = reqtype == TR_REQ_STOPPED;
url = evbuffer_new( );
evbuffer_add_printf( url, "%s", address->announce );
@ -980,6 +987,7 @@ tr_trackerNew( const tr_torrent * torrent )
t->announceMinIntervalSec = DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC;
t->timesDownloaded = -1;
t->seederCount = -1;
t->downloaderCount = -1;
t->leecherCount = -1;
t->lastAnnounceResponse = -1;
t->lastScrapeResponse = -1;
@ -1060,9 +1068,10 @@ tr_trackerCanManualAnnounce( const tr_tracker * t )
void
tr_trackerGetCounts( const tr_tracker * t,
int * setme_completedCount,
int * setme_leecherCount,
int * setme_seederCount )
int * setme_completedCount,
int * setme_leecherCount,
int * setme_seederCount,
int * setme_downloaderCount )
{
if( setme_completedCount )
*setme_completedCount = t->timesDownloaded;
@ -1072,6 +1081,9 @@ tr_trackerGetCounts( const tr_tracker * t,
if( setme_seederCount )
*setme_seederCount = t->seederCount;
if( setme_downloaderCount )
*setme_downloaderCount = t->downloaderCount;
}
void

View File

@ -97,6 +97,7 @@ time_t tr_trackerGetManualAnnounceTime( const struct tr_tracker
void tr_trackerGetCounts( const struct tr_tracker *,
int * setme_completedCount,
int * setme_leecherCount,
int * setme_seederCount );
int * setme_seederCount,
int * setme_downloaderCount );
#endif

View File

@ -1323,6 +1323,11 @@ typedef struct tr_stat
/** Number of leechers that the tracker says this torrent has */
int leechers;
/** Number of downloaders that the tracker says this torrent has.
This is a new key introduced in BEP 21 and may not be supported by some trackers.
If the tracker doesn't support this key, the value here will be -1. */
int downloaders;
/** Number of finished downloads that the tracker says torrent has */
int timesCompleted;

View File

@ -51,7 +51,7 @@ struct tr_webseed
****
***/
static const tr_peer_event blankEvent = { 0, 0, 0, 0, 0.0f, 0, 0 };
static const tr_peer_event blankEvent = { 0, 0, 0, 0, 0.0f, 0, 0, 0 };
static void
publish( tr_webseed * w,