#define DEFAULT_HOST "localhost"
#define DEFAULT_PORT TR_DEFAULT_RPC_PORT
-enum { TAG_LIST, TAG_DETAILS, TAG_FILES };
+enum { TAG_LIST, TAG_DETAILS, TAG_FILES, TAG_PEERS };
static const char*
getUsage( void )
{ 'w', "download-dir", "Set the default download folder", "w", 1, "<path>" },
{ 'x', "pex", "Enable peer exchange (PEX)", "x", 0, NULL },
{ 'X', "no-pex", "Disable peer exchange (PEX)", "X", 0, NULL },
+ { 'z', "peers", "List the current torrent's peers", "z", 0, NULL },
{ 0, NULL, NULL, NULL, 0, NULL }
};
case 'X': tr_bencDictAddStr( &top, "method", "session-set" );
tr_bencDictAddInt( args, "pex-allowed", 0 );
break;
+ case 'z': tr_bencDictAddStr( &top, "method", "torrent-get" );
+ tr_bencDictAddInt( &top, "tag", TAG_PEERS );
+ fields = tr_bencDictAddList( args, "fields", 1 );
+ tr_bencListAddStr( fields, "peers" );
+ break;
case 900: tr_bencDictAddStr( &top, "method", "torrent-set" );
addIdArg( args, id );
addFiles( args, "priority-high", optarg );
}
}
+static void
+printPeerList( tr_benc * top )
+{
+ tr_benc *args, *list;
+
+ if( ( tr_bencDictFindDict( top, "arguments", &args ) ) &&
+ ( tr_bencDictFindList( args, "peers", &list ) ) )
+ {
+ int i, n;
+ printf( "%-20s %-12s %-5s %5s %s\n",
+ "Address", "Flags", "Down", "Up", "Client" );
+ for( i=0, n=tr_bencListSize( list ); i<n; ++i )
+ {
+ const char * address, * client, * flagstr;
+ int64_t rateToClient, rateToPeer;
+ tr_benc * d = tr_bencListChild( list, i );
+ if( tr_bencDictFindStr( d, "address", &address )
+ && tr_bencDictFindStr( d, "client", &client )
+ && tr_bencDictFindStr( d, "flagstr", &flagstr )
+ && tr_bencDictFindInt( d, "rateToClient", &rateToClient )
+ && tr_bencDictFindInt( d, "rateToPeer", &rateToPeer ) )
+ {
+ printf( "%-20s %-12s %5.1f %5.1f %s\n",
+ address, flagstr,
+ rateToClient * 1024.0,
+ rateToPeer * 1024.0,
+ client );
+ }
+ }
+ }
+}
+
static void
printTorrentList( tr_benc * top )
{
case TAG_FILES: printFileList( &top ); break;
case TAG_DETAILS: printDetails( &top ); break;
case TAG_LIST: printTorrentList( &top ); break;
+ case TAG_PEERS: printPeerList( &top ); break;
default: if( tr_bencDictFindStr( &top, "result", &str ) )
printf( "%s:%d responded: \"%s\"\n", host, port, str );
}
.Op Fl v
.Op Fl w Ar download-dir
.Op Fl x | X
+.Op Fl z | peers
.Ek
.Sh DESCRIPTION
.Nm
.It Fl X Fl -no-pex
Disable peer exchange (PEX).
+.It Fl x Fl -peers
+List the current torrent's connected peers.
+In the `status' section of the list, the following shorthand is used:
+.D1 D: Downloading from this peer
+.D1 d: We would download from this peer if they would let us
+.D1 E: Encrypted connection
+.D1 I: Peer is an incoming connection
+.D1 K: Peer has unchoked us, but we're not interested
+.D1 O: Optimistic unchoked
+.D1 U: Uploading to peer
+.D1 u: We would upload to this peer if they asked
+.D1 X: Peer was discovered through Peer Exchange (PEX)
+.D1 ?: We unchoked this peer, but they're not interested
+
.El
.Sh EXAMPLES
name | string | tr_info
nextAnnounceTime | number | tr_stat
nextScrapeTime | number | tr_stat
+ peers | array (see below) | n/a
peersConnected | number | tr_stat
peersFrom | object (see below) | n/a
peersGettingFromUs | number | tr_stat
pieceCount | tnumber | tr_info
pieceSize | tnumber | tr_info
priorities | array (see below) | n/a
- rateDownload | number | tr_stat
- rateUpload | number | tr_stat
+ rateDownload (B/s) | number | tr_stat
+ rateUpload (B/s) | number | tr_stat
recheckProgress | number | tr_stat
scrapeResponse | string | tr_stat
scrapeURL | string | tr_stat
| |
-----------------------+--------------------------------------+
files | array of objects, each containing: |
- +------------------+-------------------+
- | key | type |
- | bytesCompleted | number | tr_torrent
- | length | number | tr_info
- | name | string | tr_info
+ +-------------------------+------------+
+ | key | type |
+ | bytesCompleted | number | tr_torrent
+ | length | number | tr_info
+ | name | string | tr_info
+ -----------------------+--------------------------------------+
+ peers | array of objects, each containing: |
+ +-------------------------+------------+
+ | address | string | tr_peer_stat
+ | clientName | string | tr_peer_stat
+ | clientIsChoked | 'boolean' | tr_peer_stat
+ | clientIsInterested | 'boolean' | tr_peer_stat
+ | isDownloadingFrom | 'boolean' | tr_peer_stat
+ | isEncrypted | 'boolean' | tr_peer_stat
+ | isIncoming | 'boolean' | tr_peer_stat
+ | isUploadingTo | 'boolean' | tr_peer_stat
+ | peerIsChoked | 'boolean' | tr_peer_stat
+ | peerIsInterested | 'boolean' | tr_peer_stat
+ | progress | 'double' | tr_peer_stat
+ | rateToClient (B/s) | number | tr_peer_stat
+ | rateToPeer (B/s) | number | tr_peer_stat
-----------------------+--------------------------------------+
peersFrom | an object containing: |
- +------------------+-------------------+
- | fromCache | number | tr_stat
- | fromIncoming | number | tr_stat
- | fromPex | number | tr_stat
- | fromTracker | number | tr_stat
+ +-------------------------+------------+
+ | fromCache | number | tr_stat
+ | fromIncoming | number | tr_stat
+ | fromPex | number | tr_stat
+ | fromTracker | number | tr_stat
-----------------------+--------------------------------------+
priorities | an array of tr_info.filecount | tr_info
| numbers. each is the tr_priority_t |
| mode for the corresponding file. |
-----------------------+--------------------------------------+
trackers | array of objects, each containing: |
- +------------------+-------------------+
- | announce | string | tr_info
- | scrape | string | tr_info
- | tier | number | tr_info
+ +-------------------------+------------+
+ | announce | string | tr_info
+ | scrape | string | tr_info
+ | tier | number | tr_info
-----------------------+--------------------------------------+
wanted | an array of tr_info.fileCount | tr_info
| 'booleans' true if the corresponding |
| file is to be downloaded. |
-----------------------+--------------------------------------+
webseeds | an array of strings: |
- +------------------+-------------------+
- | webseed | string | tr_info
- +------------------+-------------------+
+ +-------------------------+------------+
+ | webseed | string | tr_info
+ +-------------------------+------------+
Example:
PEER_COL_CLIENT, client,
PEER_COL_IS_ENCRYPTED, peer->isEncrypted,
PEER_COL_PROGRESS, (int)(100.0*peer->progress),
- PEER_COL_DOWNLOAD_RATE, peer->downloadFromRate,
- PEER_COL_UPLOAD_RATE, peer->uploadToRate,
+ PEER_COL_DOWNLOAD_RATE, peer->rateToClient,
+ PEER_COL_UPLOAD_RATE, peer->rateToPeer,
PEER_COL_STATUS, peer->flagStr,
-1);
}
TR_ADDREQ_DUPLICATE,
TR_ADDREQ_MISSING,
TR_ADDREQ_CLIENT_CHOKED
-} tr_addreq_t;
+}
+tr_addreq_t;
/**
*** Peer Publish / Subscribe
stat->from = atom->from;
stat->progress = peer->progress;
stat->isEncrypted = tr_peerIoIsEncrypted( peer->io ) ? 1 : 0;
- stat->uploadToRate = peer->rateToPeer;
- stat->downloadFromRate = peer->rateToClient;
+ stat->rateToPeer = peer->rateToPeer;
+ stat->rateToClient = peer->rateToClient;
stat->peerIsChoked = peer->peerIsChoked;
stat->peerIsInterested = peer->peerIsInterested;
stat->clientIsChoked = peer->clientIsChoked;
}
}
+static void
+addPeers( const tr_torrent * tor, tr_benc * list )
+{
+ int i;
+ int peerCount;
+ tr_peer_stat * peers = tr_torrentPeers( tor, &peerCount );
+
+ tr_bencInitList( list, peerCount );
+
+ for( i=0; i<peerCount; ++i )
+ {
+ tr_benc * d = tr_bencListAddDict( list, 14 );
+ const tr_peer_stat * peer = peers + i;
+ tr_bencDictAddStr( d, "address", peer->addr );
+ tr_bencDictAddStr( d, "clientName", peer->client );
+ tr_bencDictAddInt( d, "clientIsChoked", peer->clientIsChoked );
+ tr_bencDictAddInt( d, "clientIsInterested", peer->clientIsInterested );
+ tr_bencDictAddStr( d, "flagStr", peer->flagStr );
+ tr_bencDictAddInt( d, "isDownloadingFrom", peer->isDownloadingFrom );
+ tr_bencDictAddInt( d, "isEncrypted", peer->isEncrypted );
+ tr_bencDictAddInt( d, "isIncoming", peer->isIncoming );
+ tr_bencDictAddInt( d, "isUploadingTo", peer->isUploadingTo );
+ tr_bencDictAddInt( d, "peerIsChoked", peer->peerIsChoked );
+ tr_bencDictAddInt( d, "peerIsInterested", peer->peerIsInterested );
+ tr_bencDictAddDouble( d, "progress", peer->progress );
+ tr_bencDictAddInt( d, "rateToClient", (int)(peer->rateToClient*1024.0) );
+ tr_bencDictAddInt( d, "rateToPeer", (int)(peer->rateToPeer*1024.0) );
+ }
+
+ tr_torrentPeersFree( peers, peerCount );
+}
+
static void
addField( const tr_torrent * tor, tr_benc * d, const char * key )
{
tr_bencDictAddInt( d, key, st->nextAnnounceTime );
else if( !strcmp( key, "nextScrapeTime" ) )
tr_bencDictAddInt( d, key, st->nextScrapeTime );
+ else if( !strcmp( key, "peers" ) )
+ addPeers( tor, tr_bencDictAdd( d, key ) );
else if( !strcmp( key, "peersConnected" ) )
tr_bencDictAddInt( d, key, st->peersConnected );
else if( !strcmp( key, "peersFrom" ) ) {
signal( SIGPIPE, SIG_IGN );
#endif
-abort();
-
tr_msgInit( );
tr_setMessageLevel( messageLevel );
tr_setMessageQueuing( isMessageQueueingEnabled );
char flagStr[32];
float progress;
- float downloadFromRate;
- float uploadToRate;
+ float rateToPeer;
+ float rateToClient;
}
tr_peer_stat;
[dict setObject: [NSString stringWithUTF8String: peer->flagStr] forKey: @"Flags"];
if (peer->isUploadingTo)
- [dict setObject: [NSNumber numberWithFloat: peer->uploadToRate] forKey: @"UL To Rate"];
+ [dict setObject: [NSNumber numberWithFloat: peer->rateToPeer] forKey: @"UL To Rate"];
if (peer->isDownloadingFrom)
- [dict setObject: [NSNumber numberWithFloat: peer->downloadFromRate] forKey: @"DL From Rate"];
+ [dict setObject: [NSNumber numberWithFloat: peer->rateToClient] forKey: @"DL From Rate"];
[peerDicts addObject: dict];
}