mirror of https://github.com/aria2/aria2
2006-10-20 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
To simplify TrackerWatherCommand, TrackerUpdateCommand and make the process of announce request testable. * src/TrackerWatcherCommand.h (TimeA2.h): Removed. (interval): Removed. (checkPoint): Removed. (createRequestCommand): Added an argument 'url'. (TrackerWatherCommand): Removed interval. (createCommand): New function. * src/DownloadEngineFactory.cc (newTorrentConsoleEngine): Updated according to the changes in TrackerWatherCommand. * src/TorrentMan.cc (DelegatingPeerListProcessor.h): New includes. (TorrentMan): Added the initialization of announceInterval. (isStoppedAnnounceReady): New function. (isCompletedAnnounceReady): New function. (isDefaultAnnounceReady): New function. (isAnnounceReady): New function. (getAnnounceUrl): New function. (announceStart): New function. (announceFailure): New function. (announceSuccess): New function. (isAllAnnounceFailed): New function. (resetAnnounce): New function. (processAnnounceResponse): New function. (needMorePeerConnection): New function. (noMoreAnnounce): New function. * src/TrackerUpdateCommand.h (getTrackerResponse): int->size_t * src/TorrentMan.h (isStoppedAnnounceReady): New function. (isCompletedAnnounceReady): New function. (isDefaultAnnounceReady): New function. (announceInterval): New variable. (isAnnounceReady): New function. (getAnnounceUrl): New function. (announceStart): New function. (announceFailure): New function. (announceSuccess): New function. (isAllAnnounceFailed): New function. (resetAnnounce): New function. (processAnnounceResponse): New function. (needMorePeerConnection): New function. (noMoreAnnounce): New function. * src/TrackerWatcherCommand.cc (TrackerWatherCommand): Removed interval and checkPoint. (execute): Rewritten. (createCommand): New function. (createRequestCommand): Rewritten. * src/TrackerUpdateCommand.cc (MetaFileUtil.h): Removed. (DelegatingPeerListProcessor.h): Removed. (getTrackerResponse): int->size_t. Use torrentMan's new functions.pull/1/head
parent
c0fd1fff2a
commit
b8737b0e7c
58
ChangeLog
58
ChangeLog
|
@ -1,3 +1,61 @@
|
||||||
|
2006-10-20 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
||||||
|
|
||||||
|
To simplify TrackerWatherCommand, TrackerUpdateCommand and
|
||||||
|
make the process of announce request testable.
|
||||||
|
|
||||||
|
* src/TrackerWatcherCommand.h
|
||||||
|
(TimeA2.h): Removed.
|
||||||
|
(interval): Removed.
|
||||||
|
(checkPoint): Removed.
|
||||||
|
(createRequestCommand): Added an argument 'url'.
|
||||||
|
(TrackerWatherCommand): Removed interval.
|
||||||
|
(createCommand): New function.
|
||||||
|
* src/DownloadEngineFactory.cc
|
||||||
|
(newTorrentConsoleEngine): Updated according to the changes in
|
||||||
|
TrackerWatherCommand.
|
||||||
|
* src/TorrentMan.cc
|
||||||
|
(DelegatingPeerListProcessor.h): New includes.
|
||||||
|
(TorrentMan): Added the initialization of announceInterval.
|
||||||
|
(isStoppedAnnounceReady): New function.
|
||||||
|
(isCompletedAnnounceReady): New function.
|
||||||
|
(isDefaultAnnounceReady): New function.
|
||||||
|
(isAnnounceReady): New function.
|
||||||
|
(getAnnounceUrl): New function.
|
||||||
|
(announceStart): New function.
|
||||||
|
(announceFailure): New function.
|
||||||
|
(announceSuccess): New function.
|
||||||
|
(isAllAnnounceFailed): New function.
|
||||||
|
(resetAnnounce): New function.
|
||||||
|
(processAnnounceResponse): New function.
|
||||||
|
(needMorePeerConnection): New function.
|
||||||
|
(noMoreAnnounce): New function.
|
||||||
|
* src/TrackerUpdateCommand.h
|
||||||
|
(getTrackerResponse): int->size_t
|
||||||
|
* src/TorrentMan.h
|
||||||
|
(isStoppedAnnounceReady): New function.
|
||||||
|
(isCompletedAnnounceReady): New function.
|
||||||
|
(isDefaultAnnounceReady): New function.
|
||||||
|
(announceInterval): New variable.
|
||||||
|
(isAnnounceReady): New function.
|
||||||
|
(getAnnounceUrl): New function.
|
||||||
|
(announceStart): New function.
|
||||||
|
(announceFailure): New function.
|
||||||
|
(announceSuccess): New function.
|
||||||
|
(isAllAnnounceFailed): New function.
|
||||||
|
(resetAnnounce): New function.
|
||||||
|
(processAnnounceResponse): New function.
|
||||||
|
(needMorePeerConnection): New function.
|
||||||
|
(noMoreAnnounce): New function.
|
||||||
|
* src/TrackerWatcherCommand.cc
|
||||||
|
(TrackerWatherCommand): Removed interval and checkPoint.
|
||||||
|
(execute): Rewritten.
|
||||||
|
(createCommand): New function.
|
||||||
|
(createRequestCommand): Rewritten.
|
||||||
|
* src/TrackerUpdateCommand.cc
|
||||||
|
(MetaFileUtil.h): Removed.
|
||||||
|
(DelegatingPeerListProcessor.h): Removed.
|
||||||
|
(getTrackerResponse): int->size_t. Use torrentMan's new functions.
|
||||||
|
|
||||||
2006-10-18 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
2006-10-18 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
||||||
|
|
||||||
Request -> RequestHandle:
|
Request -> RequestHandle:
|
||||||
|
|
|
@ -114,8 +114,7 @@ DownloadEngineFactory::newTorrentConsoleEngine(const Option* op,
|
||||||
te->commands.push_back(listenCommand);
|
te->commands.push_back(listenCommand);
|
||||||
|
|
||||||
te->commands.push_back(new TrackerWatcherCommand(te->torrentMan->getNewCuid(),
|
te->commands.push_back(new TrackerWatcherCommand(te->torrentMan->getNewCuid(),
|
||||||
te,
|
te));
|
||||||
te->torrentMan->minInterval));
|
|
||||||
te->commands.push_back(new TrackerUpdateCommand(te->torrentMan->getNewCuid(),
|
te->commands.push_back(new TrackerUpdateCommand(te->torrentMan->getNewCuid(),
|
||||||
te));
|
te));
|
||||||
te->commands.push_back(new TorrentAutoSaveCommand(te->torrentMan->getNewCuid(),
|
te->commands.push_back(new TorrentAutoSaveCommand(te->torrentMan->getNewCuid(),
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "DirectDiskAdaptor.h"
|
#include "DirectDiskAdaptor.h"
|
||||||
#include "MultiDiskAdaptor.h"
|
#include "MultiDiskAdaptor.h"
|
||||||
#include "LogFactory.h"
|
#include "LogFactory.h"
|
||||||
|
#include "DelegatingPeerListProcessor.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -76,6 +77,8 @@ TorrentMan::TorrentMan():bitfield(0),
|
||||||
diskAdaptor(0)
|
diskAdaptor(0)
|
||||||
{
|
{
|
||||||
logger = LogFactory::getInstance();
|
logger = LogFactory::getInstance();
|
||||||
|
// to force requesting to a tracker first time.
|
||||||
|
announceInterval.setTimeInSec(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TorrentMan::~TorrentMan() {
|
TorrentMan::~TorrentMan() {
|
||||||
|
@ -751,3 +754,158 @@ TransferStat TorrentMan::calculateStat() {
|
||||||
}
|
}
|
||||||
return stat;
|
return stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TorrentMan::isStoppedAnnounceReady() const {
|
||||||
|
return (trackers == 0 &&
|
||||||
|
isHalt() &&
|
||||||
|
announceList.countStoppedAllowedTier());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TorrentMan::isCompletedAnnounceReady() const {
|
||||||
|
return (trackers == 0 &&
|
||||||
|
downloadComplete() &&
|
||||||
|
announceList.countCompletedAllowedTier());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TorrentMan::isDefaultAnnounceReady() const {
|
||||||
|
return (trackers == 0 &&
|
||||||
|
announceInterval.elapsed(minInterval));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TorrentMan::isAnnounceReady() const {
|
||||||
|
return
|
||||||
|
isStoppedAnnounceReady() ||
|
||||||
|
isCompletedAnnounceReady() ||
|
||||||
|
isDefaultAnnounceReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
string TorrentMan::getAnnounceUrl() {
|
||||||
|
if(isStoppedAnnounceReady()) {
|
||||||
|
announceList.moveToStoppedAllowedTier();
|
||||||
|
announceList.setEvent(AnnounceTier::STOPPED);
|
||||||
|
} else if(isCompletedAnnounceReady()) {
|
||||||
|
announceList.moveToCompletedAllowedTier();
|
||||||
|
announceList.setEvent(AnnounceTier::COMPLETED);
|
||||||
|
} else if(isDefaultAnnounceReady()) {
|
||||||
|
// If download completed before "started" event is sent to a tracker,
|
||||||
|
// we change the event to something else to prevent us from
|
||||||
|
// sending "completed" event.
|
||||||
|
if(downloadComplete() &&
|
||||||
|
announceList.getEvent() == AnnounceTier::STARTED) {
|
||||||
|
announceList.setEvent(AnnounceTier::STARTED_AFTER_COMPLETION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int numWant = 50;
|
||||||
|
if(connections >= MIN_PEERS || isHalt()) {
|
||||||
|
numWant = 0;
|
||||||
|
}
|
||||||
|
string url = announceList.getAnnounce()+"?"+
|
||||||
|
"info_hash="+Util::torrentUrlencode(getInfoHash(), 20)+"&"+
|
||||||
|
"peer_id="+peerId+"&"+
|
||||||
|
"port="+Util::itos(getPort())+"&"+
|
||||||
|
"uploaded="+Util::llitos(getSessionUploadLength())+"&"+
|
||||||
|
"downloaded="+Util::llitos(getSessionDownloadLength())+"&"+
|
||||||
|
"left="+(getTotalLength()-getDownloadLength() <= 0
|
||||||
|
? "0" : Util::llitos(getTotalLength()-getDownloadLength()))+"&"+
|
||||||
|
"compact=1"+"&"+
|
||||||
|
"key="+key+"&"+
|
||||||
|
"numwant="+Util::itos(numWant)+"&"+
|
||||||
|
"no_peer_id=1";
|
||||||
|
string event = announceList.getEventString();
|
||||||
|
if(!event.empty()) {
|
||||||
|
url += string("&")+"event="+event;
|
||||||
|
}
|
||||||
|
if(!trackerId.empty()) {
|
||||||
|
url += string("&")+"trackerid="+trackerId;
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TorrentMan::announceStart() {
|
||||||
|
trackers++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TorrentMan::announceFailure() {
|
||||||
|
trackers = 0;
|
||||||
|
trackerNumTry++;
|
||||||
|
announceList.announceFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TorrentMan::announceSuccess() {
|
||||||
|
trackers = 0;
|
||||||
|
announceList.announceSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TorrentMan::isAllAnnounceFailed() const {
|
||||||
|
return
|
||||||
|
trackerNumTry >= option->getAsInt(PREF_TRACKER_MAX_TRIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TorrentMan::resetAnnounce() {
|
||||||
|
announceInterval.reset();
|
||||||
|
trackerNumTry = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TorrentMan::processAnnounceResponse(const char* trackerResponse,
|
||||||
|
size_t trackerResponseLength) {
|
||||||
|
SharedHandle<MetaEntry> entry(MetaFileUtil::bdecoding(trackerResponse,
|
||||||
|
trackerResponseLength));
|
||||||
|
Dictionary* response = (Dictionary*)entry.get();
|
||||||
|
Data* failureReasonData = (Data*)response->get("failure reason");
|
||||||
|
if(failureReasonData) {
|
||||||
|
throw new DlAbortEx("Tracker returned failure reason: %s",
|
||||||
|
failureReasonData->toString().c_str());
|
||||||
|
}
|
||||||
|
Data* warningMessageData = (Data*)response->get("warning message");
|
||||||
|
if(warningMessageData) {
|
||||||
|
logger->warn(MSG_TRACKER_WARNING_MESSAGE,
|
||||||
|
warningMessageData->toString().c_str());
|
||||||
|
}
|
||||||
|
Data* trackerIdData = (Data*)response->get("tracker id");
|
||||||
|
if(trackerIdData) {
|
||||||
|
trackerId = trackerIdData->toString();
|
||||||
|
logger->debug("Tracker ID:%s", trackerId.c_str());
|
||||||
|
}
|
||||||
|
Data* intervalData = (Data*)response->get("interval");
|
||||||
|
if(intervalData) {
|
||||||
|
interval = intervalData->toInt();
|
||||||
|
logger->debug("Interval:%d", interval);
|
||||||
|
}
|
||||||
|
Data* minIntervalData = (Data*)response->get("min interval");
|
||||||
|
if(minIntervalData) {
|
||||||
|
minInterval = minIntervalData->toInt();
|
||||||
|
logger->debug("Min interval:%d", minInterval);
|
||||||
|
}
|
||||||
|
if(minInterval > interval) {
|
||||||
|
minInterval = interval;
|
||||||
|
}
|
||||||
|
Data* completeData = (Data*)response->get("complete");
|
||||||
|
if(completeData) {
|
||||||
|
complete = completeData->toInt();
|
||||||
|
logger->debug("Complete:%d", complete);
|
||||||
|
}
|
||||||
|
Data* incompleteData = (Data*)response->get("incomplete");
|
||||||
|
if(incompleteData) {
|
||||||
|
incomplete = incompleteData->toInt();
|
||||||
|
logger->debug("Incomplete:%d", incomplete);
|
||||||
|
}
|
||||||
|
const MetaEntry* peersEntry = response->get("peers");
|
||||||
|
if(peersEntry && !isHalt() && connections < MIN_PEERS) {
|
||||||
|
DelegatingPeerListProcessor proc(pieceLength, getTotalLength());
|
||||||
|
Peers peers = proc.extractPeer(peersEntry);
|
||||||
|
addPeer(peers);
|
||||||
|
}
|
||||||
|
if(!peersEntry) {
|
||||||
|
logger->info("No peer list received.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TorrentMan::needMorePeerConnection() const {
|
||||||
|
return isPeerAvailable() && connections < MIN_PEERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TorrentMan::noMoreAnnounce() const {
|
||||||
|
return (trackers == 0 &&
|
||||||
|
isHalt() &&
|
||||||
|
!announceList.countStoppedAllowedTier());
|
||||||
|
}
|
||||||
|
|
|
@ -126,6 +126,10 @@ private:
|
||||||
void setupInternal1(const string& metaInfoFile);
|
void setupInternal1(const string& metaInfoFile);
|
||||||
void setupInternal2();
|
void setupInternal2();
|
||||||
Piece checkOutPiece(int index);
|
Piece checkOutPiece(int index);
|
||||||
|
bool isStoppedAnnounceReady() const;
|
||||||
|
bool isCompletedAnnounceReady() const;
|
||||||
|
bool isDefaultAnnounceReady() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int pieceLength;
|
int pieceLength;
|
||||||
int pieces;
|
int pieces;
|
||||||
|
@ -143,6 +147,7 @@ public:
|
||||||
// The number of tracker request command currently in the command queue.
|
// The number of tracker request command currently in the command queue.
|
||||||
int trackers;
|
int trackers;
|
||||||
int trackerNumTry;
|
int trackerNumTry;
|
||||||
|
Time announceInterval;
|
||||||
// tracker request
|
// tracker request
|
||||||
AnnounceList announceList;
|
AnnounceList announceList;
|
||||||
public:
|
public:
|
||||||
|
@ -297,6 +302,18 @@ public:
|
||||||
void setHalt(bool halt) {
|
void setHalt(bool halt) {
|
||||||
this->halt = halt;
|
this->halt = halt;
|
||||||
}
|
}
|
||||||
|
// announce related methods.
|
||||||
|
bool isAnnounceReady() const;
|
||||||
|
string getAnnounceUrl();
|
||||||
|
void announceStart();
|
||||||
|
void announceSuccess();
|
||||||
|
void announceFailure();
|
||||||
|
bool isAllAnnounceFailed() const;
|
||||||
|
void resetAnnounce();
|
||||||
|
void processAnnounceResponse(const char* trackerResponse,
|
||||||
|
size_t trackerResponseLength);
|
||||||
|
bool needMorePeerConnection() const;
|
||||||
|
bool noMoreAnnounce() const;
|
||||||
|
|
||||||
enum FILE_MODE {
|
enum FILE_MODE {
|
||||||
SINGLE,
|
SINGLE,
|
||||||
|
|
|
@ -34,15 +34,13 @@
|
||||||
/* copyright --> */
|
/* copyright --> */
|
||||||
#include "TrackerUpdateCommand.h"
|
#include "TrackerUpdateCommand.h"
|
||||||
#include "LogFactory.h"
|
#include "LogFactory.h"
|
||||||
#include "MetaFileUtil.h"
|
|
||||||
#include "DlAbortEx.h"
|
#include "DlAbortEx.h"
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
#include "PeerInitiateConnectionCommand.h"
|
#include "PeerInitiateConnectionCommand.h"
|
||||||
#include "SleepCommand.h"
|
#include "SleepCommand.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "DelegatingPeerListProcessor.h"
|
|
||||||
|
|
||||||
TrackerUpdateCommand::TrackerUpdateCommand(int cuid, TorrentDownloadEngine*e):Command(cuid), e(e) {
|
TrackerUpdateCommand::TrackerUpdateCommand(int cuid, TorrentDownloadEngine* e):Command(cuid), e(e) {
|
||||||
logger = LogFactory::getInstance();
|
logger = LogFactory::getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +51,7 @@ bool TrackerUpdateCommand::prepareForRetry() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* TrackerUpdateCommand::getTrackerResponse(int& trackerResponseLength) {
|
char* TrackerUpdateCommand::getTrackerResponse(size_t& trackerResponseLength) {
|
||||||
int maxBufLength = 2048;
|
int maxBufLength = 2048;
|
||||||
char* buf = new char[maxBufLength];
|
char* buf = new char[maxBufLength];
|
||||||
int bufLength = 0;
|
int bufLength = 0;
|
||||||
|
@ -86,77 +84,24 @@ bool TrackerUpdateCommand::execute() {
|
||||||
return prepareForRetry();
|
return prepareForRetry();
|
||||||
}
|
}
|
||||||
char* trackerResponse = NULL;
|
char* trackerResponse = NULL;
|
||||||
int trackerResponseLength = 0;
|
size_t trackerResponseLength = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
trackerResponse = getTrackerResponse(trackerResponseLength);
|
trackerResponse = getTrackerResponse(trackerResponseLength);
|
||||||
SharedHandle<MetaEntry> entry(MetaFileUtil::bdecoding(trackerResponse,
|
|
||||||
trackerResponseLength));
|
|
||||||
Dictionary* response = (Dictionary*)entry.get();
|
|
||||||
Data* failureReason = (Data*)response->get("failure reason");
|
|
||||||
if(failureReason != NULL) {
|
|
||||||
throw new DlAbortEx("Tracker returned failure reason: %s", failureReason->toString().c_str());
|
|
||||||
}
|
|
||||||
Data* warningMessage = (Data*)response->get("warning message");
|
|
||||||
if(warningMessage != NULL) {
|
|
||||||
logger->warn(MSG_TRACKER_WARNING_MESSAGE, warningMessage->toString().c_str());
|
|
||||||
}
|
|
||||||
Data* trackerId = (Data*)response->get("tracker id");
|
|
||||||
if(trackerId != NULL) {
|
|
||||||
e->torrentMan->trackerId = trackerId->toString();
|
|
||||||
logger->debug("CUID#%d - Tracker ID:%s",
|
|
||||||
cuid, e->torrentMan->trackerId.c_str());
|
|
||||||
}
|
|
||||||
Data* interval = (Data*)response->get("interval");
|
|
||||||
if(interval != NULL) {
|
|
||||||
e->torrentMan->interval = interval->toInt();
|
|
||||||
logger->debug("CUID#%d - Interval:%d", cuid, e->torrentMan->interval);
|
|
||||||
}
|
|
||||||
Data* minInterval = (Data*)response->get("min interval");
|
|
||||||
if(minInterval != NULL) {
|
|
||||||
e->torrentMan->minInterval = minInterval->toInt();
|
|
||||||
logger->debug("CUID#%d - Min interval:%d",
|
|
||||||
cuid, e->torrentMan->minInterval);
|
|
||||||
}
|
|
||||||
if(e->torrentMan->minInterval > e->torrentMan->interval) {
|
|
||||||
e->torrentMan->minInterval = e->torrentMan->interval;
|
|
||||||
}
|
|
||||||
Data* complete = (Data*)response->get("complete");
|
|
||||||
if(complete != NULL) {
|
|
||||||
e->torrentMan->complete = complete->toInt();
|
|
||||||
logger->debug("CUID#%d - Complete:%d", cuid, e->torrentMan->complete);
|
|
||||||
}
|
|
||||||
Data* incomplete = (Data*)response->get("incomplete");
|
|
||||||
if(incomplete != NULL) {
|
|
||||||
e->torrentMan->incomplete = incomplete->toInt();
|
|
||||||
logger->debug("CUID#%d - Incomplete:%d",
|
|
||||||
cuid, e->torrentMan->incomplete);
|
|
||||||
}
|
|
||||||
const MetaEntry* peersEntry = response->get("peers");
|
|
||||||
if(!e->torrentMan->isHalt() &&
|
|
||||||
e->torrentMan->connections < MIN_PEERS &&
|
|
||||||
peersEntry) {
|
|
||||||
DelegatingPeerListProcessor proc(e->torrentMan->pieceLength,
|
|
||||||
e->torrentMan->getTotalLength());
|
|
||||||
Peers peers = proc.extractPeer(peersEntry);
|
|
||||||
e->torrentMan->addPeer(peers);
|
|
||||||
|
|
||||||
while(e->torrentMan->isPeerAvailable() &&
|
e->torrentMan->processAnnounceResponse(trackerResponse,
|
||||||
e->torrentMan->connections < MIN_PEERS) {
|
trackerResponseLength);
|
||||||
PeerHandle peer = e->torrentMan->getPeer();
|
while(e->torrentMan->needMorePeerConnection()) {
|
||||||
int newCuid = e->torrentMan->getNewCuid();
|
PeerHandle peer = e->torrentMan->getPeer();
|
||||||
peer->cuid = newCuid;
|
int newCuid = e->torrentMan->getNewCuid();
|
||||||
PeerInitiateConnectionCommand* command =
|
peer->cuid = newCuid;
|
||||||
new PeerInitiateConnectionCommand(newCuid, peer, e);
|
PeerInitiateConnectionCommand* command =
|
||||||
e->commands.push_back(command);
|
new PeerInitiateConnectionCommand(newCuid, peer, e);
|
||||||
logger->debug("CUID#%d - Adding new command CUID#%d", cuid, newCuid);
|
e->commands.push_back(command);
|
||||||
}
|
logger->debug("CUID#%d - Adding new command CUID#%d", cuid, newCuid);
|
||||||
}
|
}
|
||||||
if(!peersEntry) {
|
e->torrentMan->announceSuccess();
|
||||||
logger->info("CUID#%d - No peer list received.", cuid);
|
e->torrentMan->resetAnnounce();
|
||||||
}
|
|
||||||
e->torrentMan->announceList.announceSuccess();
|
|
||||||
e->torrentMan->trackers = 0;
|
|
||||||
e->segmentMan->init();
|
e->segmentMan->init();
|
||||||
} catch(Exception* err) {
|
} catch(Exception* err) {
|
||||||
logger->error("CUID#%d - Error occurred while processing tracker response.", cuid, err);
|
logger->error("CUID#%d - Error occurred while processing tracker response.", cuid, err);
|
||||||
|
|
|
@ -44,7 +44,7 @@ private:
|
||||||
TorrentDownloadEngine* e;
|
TorrentDownloadEngine* e;
|
||||||
const Logger* logger;
|
const Logger* logger;
|
||||||
bool prepareForRetry();
|
bool prepareForRetry();
|
||||||
char* getTrackerResponse(int& trackerResponseLength);
|
char* getTrackerResponse(size_t& trackerResponseLength);
|
||||||
public:
|
public:
|
||||||
TrackerUpdateCommand(int cuid, TorrentDownloadEngine* e);
|
TrackerUpdateCommand(int cuid, TorrentDownloadEngine* e);
|
||||||
virtual ~TrackerUpdateCommand();
|
virtual ~TrackerUpdateCommand();
|
||||||
|
|
|
@ -39,103 +39,48 @@
|
||||||
#include "prefs.h"
|
#include "prefs.h"
|
||||||
|
|
||||||
TrackerWatcherCommand::TrackerWatcherCommand(int cuid,
|
TrackerWatcherCommand::TrackerWatcherCommand(int cuid,
|
||||||
TorrentDownloadEngine* e,
|
TorrentDownloadEngine* e):
|
||||||
int interval):
|
Command(cuid), e(e) {
|
||||||
Command(cuid), e(e), interval(interval) {
|
|
||||||
// to force requesting to a tracker first time.
|
|
||||||
checkPoint.setTimeInSec(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackerWatcherCommand::~TrackerWatcherCommand() {}
|
TrackerWatcherCommand::~TrackerWatcherCommand() {}
|
||||||
|
|
||||||
bool TrackerWatcherCommand::execute() {
|
|
||||||
Command* command = 0;
|
|
||||||
if(e->torrentMan->trackers == 0 && e->torrentMan->isHalt()) {
|
|
||||||
// Download is going to halt.
|
|
||||||
// Check whether there are at least one tracker which can receive
|
|
||||||
// "stopped" event.
|
|
||||||
if(e->torrentMan->announceList.countStoppedAllowedTier()) {
|
|
||||||
e->torrentMan->announceList.moveToStoppedAllowedTier();
|
|
||||||
e->torrentMan->announceList.setEvent(AnnounceTier::STOPPED);
|
|
||||||
command = createRequestCommand();
|
|
||||||
} else {
|
|
||||||
// We don't send "stopped" event since no tracker cares about it.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if(e->torrentMan->trackers == 0 &&
|
|
||||||
e->torrentMan->downloadComplete() &&
|
|
||||||
e->torrentMan->announceList.countCompletedAllowedTier()) {
|
|
||||||
// Send "completed" event to all trackers which can accept it.
|
|
||||||
e->torrentMan->announceList.moveToCompletedAllowedTier();
|
|
||||||
e->torrentMan->announceList.setEvent(AnnounceTier::COMPLETED);
|
|
||||||
command = createRequestCommand();
|
|
||||||
} else if(e->torrentMan->trackers == 0 &&
|
|
||||||
checkPoint.elapsed(interval)) {
|
|
||||||
checkPoint.reset();
|
|
||||||
// If download completed before "started" event is sent to a tracker,
|
|
||||||
// we change the event to something else to prevent us from
|
|
||||||
// sending "completed" event.
|
|
||||||
if(e->torrentMan->downloadComplete() &&
|
|
||||||
e->torrentMan->announceList.getEvent() == AnnounceTier::STARTED) {
|
|
||||||
e->torrentMan->announceList.setEvent(AnnounceTier::STARTED_AFTER_COMPLETION);
|
|
||||||
}
|
|
||||||
command = createRequestCommand();
|
|
||||||
} else if(e->segmentMan->errors > 0) {
|
|
||||||
e->torrentMan->trackerNumTry++;
|
|
||||||
checkPoint.reset();
|
|
||||||
// we assume the tracker request has failed.
|
|
||||||
e->torrentMan->announceList.announceFailure();
|
|
||||||
e->torrentMan->trackers = 0;
|
|
||||||
e->segmentMan->init();
|
|
||||||
if(e->torrentMan->trackerNumTry >= e->option->getAsInt(PREF_TRACKER_MAX_TRIES)) {
|
|
||||||
// abort tracker request
|
|
||||||
e->torrentMan->trackerNumTry = 0;
|
|
||||||
if(e->torrentMan->isHalt()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// sleep a few seconds.
|
|
||||||
command =
|
|
||||||
new SleepCommand(cuid, e,
|
|
||||||
createRequestCommand(),
|
|
||||||
e->option->getAsInt(PREF_RETRY_WAIT));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
bool TrackerWatcherCommand::execute() {
|
||||||
|
if(e->torrentMan->isHalt() &&
|
||||||
|
e->segmentMan->errors > 0 && e->torrentMan->isAllAnnounceFailed() ||
|
||||||
|
e->torrentMan->noMoreAnnounce()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Command* command = createCommand();
|
||||||
if(command) {
|
if(command) {
|
||||||
e->commands.push_back(command);
|
e->commands.push_back(command);
|
||||||
e->torrentMan->trackers++;
|
|
||||||
}
|
}
|
||||||
// updates interval with newest minInterval
|
|
||||||
interval = e->torrentMan->minInterval;
|
|
||||||
e->commands.push_back(this);
|
e->commands.push_back(this);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Command* TrackerWatcherCommand::createRequestCommand() {
|
Command* TrackerWatcherCommand::createCommand() {
|
||||||
int numWant = 50;
|
Command* command = 0;
|
||||||
if(e->torrentMan->connections >= MIN_PEERS || e->torrentMan->isHalt()) {
|
if(e->torrentMan->isAnnounceReady()) {
|
||||||
numWant = 0;
|
command = createRequestCommand(e->torrentMan->getAnnounceUrl());
|
||||||
}
|
e->torrentMan->announceStart(); // inside it, trackers++.
|
||||||
string url = e->torrentMan->announceList.getAnnounce()+"?"+
|
} else if(e->segmentMan->errors > 0) {
|
||||||
"info_hash="+Util::torrentUrlencode(e->torrentMan->getInfoHash(), 20)+"&"+
|
e->torrentMan->announceFailure(); // inside it, trackers = 0.
|
||||||
"peer_id="+e->torrentMan->peerId+"&"+
|
e->segmentMan->init();
|
||||||
"port="+Util::itos(e->torrentMan->getPort())+"&"+
|
if(e->torrentMan->isAllAnnounceFailed()) {
|
||||||
"uploaded="+Util::llitos(e->torrentMan->getSessionUploadLength())+"&"+
|
e->torrentMan->resetAnnounce();
|
||||||
"downloaded="+Util::llitos(e->torrentMan->getSessionDownloadLength())+"&"+
|
// sleep a few seconds.
|
||||||
"left="+(e->torrentMan->getTotalLength()-e->torrentMan->getDownloadLength() <= 0
|
command =
|
||||||
? "0" : Util::llitos(e->torrentMan->getTotalLength()-e->torrentMan->getDownloadLength()))+"&"+
|
new SleepCommand(cuid, e,
|
||||||
"compact=1"+"&"+
|
createRequestCommand(e->torrentMan->getAnnounceUrl()),
|
||||||
"key="+e->torrentMan->key+"&"+
|
e->option->getAsInt(PREF_RETRY_WAIT));
|
||||||
"numwant="+Util::itos(numWant)+"&"+
|
}
|
||||||
"no_peer_id=1";
|
|
||||||
string event = e->torrentMan->announceList.getEventString();
|
|
||||||
if(!event.empty()) {
|
|
||||||
url += string("&")+"event="+event;
|
|
||||||
}
|
|
||||||
if(!e->torrentMan->trackerId.empty()) {
|
|
||||||
url += string("&")+"trackerid="+e->torrentMan->trackerId;
|
|
||||||
}
|
}
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
Command* TrackerWatcherCommand::createRequestCommand(const string& url) {
|
||||||
RequestHandle req;
|
RequestHandle req;
|
||||||
req->setUrl(url);
|
req->setUrl(url);
|
||||||
req->isTorrent = true;
|
req->isTorrent = true;
|
||||||
|
|
|
@ -37,19 +37,22 @@
|
||||||
|
|
||||||
#include "Command.h"
|
#include "Command.h"
|
||||||
#include "TorrentDownloadEngine.h"
|
#include "TorrentDownloadEngine.h"
|
||||||
#include "TimeA2.h"
|
|
||||||
|
|
||||||
class TrackerWatcherCommand : public Command {
|
class TrackerWatcherCommand : public Command {
|
||||||
private:
|
private:
|
||||||
TorrentDownloadEngine* e;
|
TorrentDownloadEngine* e;
|
||||||
int interval;
|
|
||||||
Time checkPoint;
|
|
||||||
|
|
||||||
Command* createRequestCommand();
|
/**
|
||||||
|
* Returns a command for announce request. Returns 0 if no announce request
|
||||||
|
* is needed.
|
||||||
|
*/
|
||||||
|
Command* createRequestCommand(const string& url);
|
||||||
public:
|
public:
|
||||||
TrackerWatcherCommand(int cuid, TorrentDownloadEngine* e, int interval);
|
TrackerWatcherCommand(int cuid, TorrentDownloadEngine* e);
|
||||||
~TrackerWatcherCommand();
|
~TrackerWatcherCommand();
|
||||||
|
|
||||||
|
Command* createCommand();
|
||||||
|
|
||||||
bool execute();
|
bool execute();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -41,16 +41,19 @@ aria2c_SOURCES = AllTest.cc\
|
||||||
SegmentManTest.cc\
|
SegmentManTest.cc\
|
||||||
SpeedCalcTest.cc\
|
SpeedCalcTest.cc\
|
||||||
DefaultPeerListProcessorTest.cc\
|
DefaultPeerListProcessorTest.cc\
|
||||||
AnnounceListTest.cc
|
AnnounceListTest.cc\
|
||||||
|
TrackerWatcherCommandTest.cc
|
||||||
#aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
|
#aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
|
||||||
#aria2c_LDFLAGS = ${CPPUNIT_LIBS}
|
#aria2c_LDFLAGS = ${CPPUNIT_LIBS}
|
||||||
|
|
||||||
aria2c_LDADD = ../src/libaria2c.a\
|
aria2c_LDADD = ../src/libaria2c.a\
|
||||||
${CPPUNIT_LIBS} @LIBGNUTLS_LIBS@\
|
${CPPUNIT_LIBS} @LIBGNUTLS_LIBS@\
|
||||||
@LIBGCRYPT_LIBS@ @OPENSSL_LIBS@ @XML_LIBS@
|
@LIBGCRYPT_LIBS@ @OPENSSL_LIBS@ @XML_LIBS@\
|
||||||
|
@LIBARES_LIBS@ @LIBCARES_LIBS@
|
||||||
AM_CPPFLAGS = -Wall\
|
AM_CPPFLAGS = -Wall\
|
||||||
${CPPUNIT_CFLAGS}\
|
${CPPUNIT_CFLAGS}\
|
||||||
-I ../src\
|
-I ../src\
|
||||||
-I../lib -I../intl -I$(top_srcdir)/intl\
|
-I../lib -I../intl -I$(top_srcdir)/intl\
|
||||||
@LIBGNUTLS_CFLAGS@ @LIBGCRYPT_CFLAGS@ @OPENSSL_CFLAGS@ @XML_CPPFLAGS@\
|
@LIBGNUTLS_CFLAGS@ @LIBGCRYPT_CFLAGS@ @OPENSSL_CFLAGS@ @XML_CPPFLAGS@\
|
||||||
|
@LIBARES_CPPFLAGS@ @LIBCARES_CPPFLAGS@\
|
||||||
-D_FILE_OFFSET_BITS=64 -DLOCALEDIR=\"$(localedir)\" @DEFS@
|
-D_FILE_OFFSET_BITS=64 -DLOCALEDIR=\"$(localedir)\" @DEFS@
|
||||||
|
|
|
@ -78,7 +78,7 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) RequestTest.$(OBJEXT) \
|
||||||
ShareRatioSeedCriteriaTest.$(OBJEXT) \
|
ShareRatioSeedCriteriaTest.$(OBJEXT) \
|
||||||
TimeSeedCriteriaTest.$(OBJEXT) SegmentManTest.$(OBJEXT) \
|
TimeSeedCriteriaTest.$(OBJEXT) SegmentManTest.$(OBJEXT) \
|
||||||
SpeedCalcTest.$(OBJEXT) DefaultPeerListProcessorTest.$(OBJEXT) \
|
SpeedCalcTest.$(OBJEXT) DefaultPeerListProcessorTest.$(OBJEXT) \
|
||||||
AnnounceListTest.$(OBJEXT)
|
AnnounceListTest.$(OBJEXT) TrackerWatcherCommandTest.$(OBJEXT)
|
||||||
aria2c_OBJECTS = $(am_aria2c_OBJECTS)
|
aria2c_OBJECTS = $(am_aria2c_OBJECTS)
|
||||||
am__DEPENDENCIES_1 =
|
am__DEPENDENCIES_1 =
|
||||||
aria2c_DEPENDENCIES = ../src/libaria2c.a $(am__DEPENDENCIES_1)
|
aria2c_DEPENDENCIES = ../src/libaria2c.a $(am__DEPENDENCIES_1)
|
||||||
|
@ -279,19 +279,22 @@ aria2c_SOURCES = AllTest.cc\
|
||||||
SegmentManTest.cc\
|
SegmentManTest.cc\
|
||||||
SpeedCalcTest.cc\
|
SpeedCalcTest.cc\
|
||||||
DefaultPeerListProcessorTest.cc\
|
DefaultPeerListProcessorTest.cc\
|
||||||
AnnounceListTest.cc
|
AnnounceListTest.cc\
|
||||||
|
TrackerWatcherCommandTest.cc
|
||||||
|
|
||||||
#aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
|
#aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
|
||||||
#aria2c_LDFLAGS = ${CPPUNIT_LIBS}
|
#aria2c_LDFLAGS = ${CPPUNIT_LIBS}
|
||||||
aria2c_LDADD = ../src/libaria2c.a\
|
aria2c_LDADD = ../src/libaria2c.a\
|
||||||
${CPPUNIT_LIBS} @LIBGNUTLS_LIBS@\
|
${CPPUNIT_LIBS} @LIBGNUTLS_LIBS@\
|
||||||
@LIBGCRYPT_LIBS@ @OPENSSL_LIBS@ @XML_LIBS@
|
@LIBGCRYPT_LIBS@ @OPENSSL_LIBS@ @XML_LIBS@\
|
||||||
|
@LIBARES_LIBS@ @LIBCARES_LIBS@
|
||||||
|
|
||||||
AM_CPPFLAGS = -Wall\
|
AM_CPPFLAGS = -Wall\
|
||||||
${CPPUNIT_CFLAGS}\
|
${CPPUNIT_CFLAGS}\
|
||||||
-I ../src\
|
-I ../src\
|
||||||
-I../lib -I../intl -I$(top_srcdir)/intl\
|
-I../lib -I../intl -I$(top_srcdir)/intl\
|
||||||
@LIBGNUTLS_CFLAGS@ @LIBGCRYPT_CFLAGS@ @OPENSSL_CFLAGS@ @XML_CPPFLAGS@\
|
@LIBGNUTLS_CFLAGS@ @LIBGCRYPT_CFLAGS@ @OPENSSL_CFLAGS@ @XML_CPPFLAGS@\
|
||||||
|
@LIBARES_CPPFLAGS@ @LIBCARES_CPPFLAGS@\
|
||||||
-D_FILE_OFFSET_BITS=64 -DLOCALEDIR=\"$(localedir)\" @DEFS@
|
-D_FILE_OFFSET_BITS=64 -DLOCALEDIR=\"$(localedir)\" @DEFS@
|
||||||
|
|
||||||
all: all-am
|
all: all-am
|
||||||
|
@ -379,6 +382,7 @@ distclean-compile:
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SuggestPieceMessageTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SuggestPieceMessageTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeSeedCriteriaTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeSeedCriteriaTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentManTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentManTest.Po@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerWatcherCommandTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnchokeMessageTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnchokeMessageTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UtilTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UtilTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xml2MetalinkProcessorTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xml2MetalinkProcessorTest.Po@am__quote@
|
||||||
|
|
|
@ -55,6 +55,6 @@ void ShaVisitorTest::testVisitCompound() {
|
||||||
int len = 0;
|
int len = 0;
|
||||||
v.getHash(md, len);
|
v.getHash(md, len);
|
||||||
string hashHex = hexHash(md, len);
|
string hashHex = hexHash(md, len);
|
||||||
CPPUNIT_ASSERT_EQUAL(string("9d33ba293924df85f6067a81c65b484de04e8efd"),
|
CPPUNIT_ASSERT_EQUAL(string("0815f9b8137fbca179c8f560e20849174e9ede8b"),
|
||||||
hashHex);
|
hashHex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
#include "TrackerWatcherCommand.h"
|
||||||
|
#include "TorrentConsoleDownloadEngine.h"
|
||||||
|
#include "MetaFileUtil.h"
|
||||||
|
#include "Exception.h"
|
||||||
|
#include "prefs.h"
|
||||||
|
#include "HttpInitiateConnectionCommand.h"
|
||||||
|
#include "ByteArrayDiskWriter.h"
|
||||||
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class TrackerWatcherCommandTest:public CppUnit::TestFixture {
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE(TrackerWatcherCommandTest);
|
||||||
|
CPPUNIT_TEST(testCreateCommand);
|
||||||
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
private:
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setUp() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void testCreateCommand();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE_REGISTRATION( TrackerWatcherCommandTest );
|
||||||
|
|
||||||
|
void TrackerWatcherCommandTest::testCreateCommand() {
|
||||||
|
try {
|
||||||
|
Option* op = new Option();
|
||||||
|
op->put(PREF_TRACKER_MAX_TRIES, "10");
|
||||||
|
|
||||||
|
TorrentConsoleDownloadEngine* te = new TorrentConsoleDownloadEngine();
|
||||||
|
te->option = op;
|
||||||
|
te->segmentMan = new SegmentMan();
|
||||||
|
te->segmentMan->option = op;
|
||||||
|
ByteArrayDiskWriter* byteArrayDiskWriter = new ByteArrayDiskWriter();
|
||||||
|
te->segmentMan->diskWriter = byteArrayDiskWriter;
|
||||||
|
te->torrentMan = new TorrentMan();
|
||||||
|
te->torrentMan->option = op;
|
||||||
|
te->torrentMan->setup("test.torrent", Strings());
|
||||||
|
|
||||||
|
TrackerWatcherCommand command(1, te);
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT(dynamic_cast<HttpInitiateConnectionCommand*>(command.createCommand()));
|
||||||
|
cerr << te->torrentMan->getAnnounceUrl() << endl;
|
||||||
|
|
||||||
|
te->torrentMan->announceSuccess();
|
||||||
|
te->torrentMan->resetAnnounce();
|
||||||
|
te->segmentMan->init();
|
||||||
|
|
||||||
|
te->torrentMan->setHalt(true);
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT(dynamic_cast<HttpInitiateConnectionCommand*>(command.createCommand()));
|
||||||
|
cerr << te->torrentMan->getAnnounceUrl() << endl;
|
||||||
|
|
||||||
|
te->torrentMan->announceSuccess();
|
||||||
|
te->torrentMan->resetAnnounce();
|
||||||
|
te->segmentMan->init();
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT(te->torrentMan->noMoreAnnounce());
|
||||||
|
|
||||||
|
} catch(Exception* e) {
|
||||||
|
cerr << e->getMsg() << endl;
|
||||||
|
delete e;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +1 @@
|
||||||
d8:announce36:http://aria.rednoah.com/announce.php7:comment17:REDNOAH.COM RULES13:creation datei1123456789e4:infod5:filesld6:lengthi256000e4:pathl5:aria23:src6:aria2ceed6:lengthi128900e4:pathl19:aria2-0.2.2.tar.bz2eee4:name10:aria2-test12:piece lengthi128e6:pieces60:AAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCee
|
d8:announce36:http://aria.rednoah.com/announce.php13:announce-listll15:http://tracker1el15:http://tracker2el15:http://tracker3ee7:comment17:REDNOAH.COM RULES13:creation datei1123456789e4:infod5:filesld6:lengthi284e4:pathl5:aria23:src6:aria2ceed6:lengthi100e4:pathl19:aria2-0.2.2.tar.bz2eee4:name10:aria2-test12:piece lengthi128e6:pieces60:AAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCee
|
Loading…
Reference in New Issue