1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2024-12-27 01:57:52 +00:00

(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_PEER_PROGRESS,
TR_PEER_ERROR, TR_PEER_ERROR,
TR_PEER_CANCEL, TR_PEER_CANCEL,
TR_PEER_UPLOAD_ONLY,
TR_PEER_NEED_REQ TR_PEER_NEED_REQ
} }
PeerEventType; PeerEventType;
@ -61,6 +62,7 @@ typedef struct
float progress; /* for PEER_PROGRESS */ float progress; /* for PEER_PROGRESS */
int err; /* errno for GOT_ERROR */ int err; /* errno for GOT_ERROR */
int wasPieceData; /* for GOT_DATA */ int wasPieceData; /* for GOT_DATA */
tr_bool uploadOnly; /* for UPLOAD_ONLY */
} }
tr_peer_event; 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 /* We keep one of these for every peer we know about, whether
* it's connected or not, so the struct must be small. * it's connected or not, so the struct must be small.
* When our current connections underperform, we dip back * When our current connections underperform, we dip back
@ -98,6 +105,8 @@ struct peer_atom
uint8_t from; uint8_t from;
uint8_t flags; /* these match the added_f flags */ uint8_t flags; /* these match the added_f flags */
uint8_t myflags; /* flags that aren't defined in added_f */ uint8_t myflags; /* flags that aren't defined in added_f */
uint8_t uploadOnly; /* UPLOAD_ONLY_ */
uint8_t partialSeed;
tr_port port; tr_port port;
uint16_t numFails; uint16_t numFails;
tr_address addr; tr_address addr;
@ -980,6 +989,14 @@ peerCallbackFunc( void * vpeer,
switch( e->eventType ) 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: case TR_PEER_NEED_REQ:
refillSoon( t ); refillSoon( t );
break; break;
@ -1458,11 +1475,15 @@ tr_peerMgrGetPeers( tr_peerMgr * manager,
for( i = 0; i < peerCount; ++i, ++walk ) for( i = 0; i < peerCount; ++i, ++walk )
{ {
const tr_peer * peer = peers[i]; const tr_peer * peer = peers[i];
const struct peer_atom * atom = getExistingAtom( t, &peer->addr );
walk->addr = peer->addr; walk->addr = peer->addr;
walk->port = peer->port; walk->port = peer->port;
walk->flags = 0; walk->flags = 0;
if( peerPrefersCrypto( peer ) ) walk->flags |= ADDED_F_ENCRYPTION_FLAG; if( peerPrefersCrypto( peer ) )
if( peer->progress >= 1.0 ) walk->flags |= ADDED_F_SEED_FLAG; 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 ); assert( ( walk - pex ) == peerCount );
@ -1884,11 +1905,22 @@ rechoke( Torrent * t )
for( i = 0, size = 0; i < peerCount; ++i ) for( i = 0, size = 0; i < peerCount; ++i )
{ {
tr_peer * peer = peers[i]; tr_peer * peer = peers[i];
struct peer_atom * atom = getExistingAtom( t, &peer->addr );
if( peer->progress >= 1.0 ) /* choke all seeds */ if( peer->progress >= 1.0 ) /* choke all seeds */
{
tr_peerMsgsSetChoke( peer->msgs, TRUE ); tr_peerMsgsSetChoke( peer->msgs, TRUE );
else if( chokeAll ) }
else if( atom->uploadOnly == UPLOAD_ONLY_YES ) /* choke partial seeds */
{
tr_peerMsgsSetChoke( peer->msgs, TRUE ); 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++]; struct ChokeData * n = &choke[size++];
n->peer = peer; n->peer = peer;
n->isInterested = peer->peerIsInterested; n->isInterested = peer->peerIsInterested;
@ -2175,7 +2207,8 @@ getPeerCandidates( Torrent * t,
continue; continue;
/* no need to connect if we're both seeds... */ /* 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; continue;
/* don't reconnect too often */ /* don't reconnect too often */

View file

@ -513,7 +513,7 @@ protocolSendHaveNone( tr_peermsgs * msgs )
*** EVENTS *** 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 static void
publish( tr_peermsgs * msgs, publish( tr_peermsgs * msgs,
@ -536,11 +536,19 @@ fireError( tr_peermsgs * msgs,
publish( msgs, &e ); 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 static void
fireNeedReq( tr_peermsgs * msgs ) fireNeedReq( tr_peermsgs * msgs )
{ {
tr_peer_event e = blankEvent; tr_peer_event e = blankEvent;
e.eventType = TR_PEER_NEED_REQ; e.eventType = TR_PEER_NEED_REQ;
publish( msgs, &e ); publish( msgs, &e );
} }
@ -1086,9 +1094,9 @@ sendLtepHandshake( tr_peermsgs * msgs )
pex = 1; pex = 1;
tr_bencInitDict( &val, 4 ); tr_bencInitDict( &val, 4 );
tr_bencDictAddInt( &val, "e", tr_bencDictAddInt( &val, "e", msgs->session->encryptionMode != TR_CLEAR_PREFERRED );
msgs->session->encryptionMode != TR_CLEAR_PREFERRED );
tr_bencDictAddInt( &val, "p", tr_sessionGetPeerPort( msgs->session ) ); 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 ); tr_bencDictAddStr( &val, "v", TR_NAME " " USERAGENT_PREFIX );
m = tr_bencDictAddDict( &val, "m", 1 ); m = tr_bencDictAddDict( &val, "m", 1 );
if( pex ) 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 */ /* get peer's listening port */
if( tr_bencDictFindInt( &val, "p", &i ) ) if( tr_bencDictFindInt( &val, "p", &i ) )
{ {

View file

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

View file

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

View file

@ -108,6 +108,7 @@ struct tr_tracker
/* these are set from the latest tracker response... -1 is 'unknown' */ /* these are set from the latest tracker response... -1 is 'unknown' */
int timesDownloaded; int timesDownloaded;
int seederCount; int seederCount;
int downloaderCount;
int leecherCount; int leecherCount;
char * trackerID; char * trackerID;
@ -583,9 +584,11 @@ onScrapeResponse( tr_session * session,
if( ( tr_bencDictFindInt( tordict, "downloaded", &itmp ) ) ) if( ( tr_bencDictFindInt( tordict, "downloaded", &itmp ) ) )
t->timesDownloaded = itmp; t->timesDownloaded = itmp;
if( ( tr_bencDictFindInt( tordict, "downloaders", &itmp ) ) )
t->downloaderCount = itmp;
if( tr_bencDictFindDict( tordict, "flags", &flags ) ) if( tr_bencDictFindDict( tordict, "flags", &flags ) )
if( ( tr_bencDictFindInt( flags, "min_request_interval", if( ( tr_bencDictFindInt( flags, "min_request_interval", &itmp ) ) )
&itmp ) ) )
t->scrapeIntervalSec = i; t->scrapeIntervalSec = i;
/* as per ticket #1045, safeguard against trackers returning /* as per ticket #1045, safeguard against trackers returning
@ -651,9 +654,9 @@ enum
TR_REQ_STARTED, TR_REQ_STARTED,
TR_REQ_COMPLETED, TR_REQ_COMPLETED,
TR_REQ_STOPPED, TR_REQ_STOPPED,
TR_REQ_PAUSED, /* BEP 21 */
TR_REQ_REANNOUNCE, TR_REQ_REANNOUNCE,
TR_REQ_SCRAPE, TR_REQ_SCRAPE
TR_REQ_COUNT
}; };
struct tr_tracker_request struct tr_tracker_request
@ -716,16 +719,20 @@ createRequest( tr_session * session,
tr_tracker * tracker, tr_tracker * tracker,
int reqtype ) int reqtype )
{ {
static const char* strings[] = static const char* strings[] = { "started", "completed", "stopped", "paused", "", "err" };
{ "started", "completed", "stopped", "", "err" }; const tr_torrent * torrent = tr_torrentFindFromHash( session, tracker->hash );
const tr_torrent * torrent = tr_torrentFindFromHash( const tr_tracker_info * address = getCurrentAddressFromTorrent( tracker, torrent );
session, tracker->hash ); int isStopping;
const tr_tracker_info * address = getCurrentAddressFromTorrent(
tracker, torrent );
const int isStopping = reqtype == TR_REQ_STOPPED;
struct tr_tracker_request * req; 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( ); url = evbuffer_new( );
evbuffer_add_printf( url, "%s", address->announce ); evbuffer_add_printf( url, "%s", address->announce );
buildTrackerRequestURI( tracker, torrent, strings[reqtype], url ); buildTrackerRequestURI( tracker, torrent, strings[reqtype], url );
@ -980,6 +987,7 @@ tr_trackerNew( const tr_torrent * torrent )
t->announceMinIntervalSec = DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC; t->announceMinIntervalSec = DEFAULT_ANNOUNCE_MIN_INTERVAL_SEC;
t->timesDownloaded = -1; t->timesDownloaded = -1;
t->seederCount = -1; t->seederCount = -1;
t->downloaderCount = -1;
t->leecherCount = -1; t->leecherCount = -1;
t->lastAnnounceResponse = -1; t->lastAnnounceResponse = -1;
t->lastScrapeResponse = -1; t->lastScrapeResponse = -1;
@ -1062,7 +1070,8 @@ void
tr_trackerGetCounts( const tr_tracker * t, tr_trackerGetCounts( const tr_tracker * t,
int * setme_completedCount, int * setme_completedCount,
int * setme_leecherCount, int * setme_leecherCount,
int * setme_seederCount ) int * setme_seederCount,
int * setme_downloaderCount )
{ {
if( setme_completedCount ) if( setme_completedCount )
*setme_completedCount = t->timesDownloaded; *setme_completedCount = t->timesDownloaded;
@ -1072,6 +1081,9 @@ tr_trackerGetCounts( const tr_tracker * t,
if( setme_seederCount ) if( setme_seederCount )
*setme_seederCount = t->seederCount; *setme_seederCount = t->seederCount;
if( setme_downloaderCount )
*setme_downloaderCount = t->downloaderCount;
} }
void void

View file

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

View file

@ -1323,6 +1323,11 @@ typedef struct tr_stat
/** Number of leechers that the tracker says this torrent has */ /** Number of leechers that the tracker says this torrent has */
int leechers; 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 */ /** Number of finished downloads that the tracker says torrent has */
int timesCompleted; 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 static void
publish( tr_webseed * w, publish( tr_webseed * w,