summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2006-10-20 13:20:50 +0000
committerTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2006-10-20 13:20:50 +0000
commitb8737b0e7c92fb4a5b1c8b6173663381aacca40c (patch)
tree0d5b0f79eb0bfbe5cda58cce30f3523c803f2d5c /src
parentc0fd1fff2a6d78d3157790bbef6f98d54f31d0fc (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/DownloadEngineFactory.cc3
-rw-r--r--src/TorrentMan.cc158
-rw-r--r--src/TorrentMan.h17
-rw-r--r--src/TrackerUpdateCommand.cc85
-rw-r--r--src/TrackerUpdateCommand.h2
-rw-r--r--src/TrackerWatcherCommand.cc107
-rw-r--r--src/TrackerWatcherCommand.h13
7 files changed, 226 insertions, 159 deletions
diff --git a/src/DownloadEngineFactory.cc b/src/DownloadEngineFactory.cc
index 4adc6d2f..6ac1d745 100644
--- a/src/DownloadEngineFactory.cc
+++ b/src/DownloadEngineFactory.cc
@@ -114,8 +114,7 @@ DownloadEngineFactory::newTorrentConsoleEngine(const Option* op,
te->commands.push_back(listenCommand);
te->commands.push_back(new TrackerWatcherCommand(te->torrentMan->getNewCuid(),
- te,
- te->torrentMan->minInterval));
+ te));
te->commands.push_back(new TrackerUpdateCommand(te->torrentMan->getNewCuid(),
te));
te->commands.push_back(new TorrentAutoSaveCommand(te->torrentMan->getNewCuid(),
diff --git a/src/TorrentMan.cc b/src/TorrentMan.cc
index fbf9b98c..c37f0c0c 100644
--- a/src/TorrentMan.cc
+++ b/src/TorrentMan.cc
@@ -49,6 +49,7 @@
#include "DirectDiskAdaptor.h"
#include "MultiDiskAdaptor.h"
#include "LogFactory.h"
+#include "DelegatingPeerListProcessor.h"
#include <errno.h>
#include <libgen.h>
#include <string.h>
@@ -76,6 +77,8 @@ TorrentMan::TorrentMan():bitfield(0),
diskAdaptor(0)
{
logger = LogFactory::getInstance();
+ // to force requesting to a tracker first time.
+ announceInterval.setTimeInSec(0);
}
TorrentMan::~TorrentMan() {
@@ -751,3 +754,158 @@ TransferStat TorrentMan::calculateStat() {
}
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());
+}
diff --git a/src/TorrentMan.h b/src/TorrentMan.h
index 240fc1c8..26ba9700 100644
--- a/src/TorrentMan.h
+++ b/src/TorrentMan.h
@@ -126,6 +126,10 @@ private:
void setupInternal1(const string& metaInfoFile);
void setupInternal2();
Piece checkOutPiece(int index);
+ bool isStoppedAnnounceReady() const;
+ bool isCompletedAnnounceReady() const;
+ bool isDefaultAnnounceReady() const;
+
public:
int pieceLength;
int pieces;
@@ -143,6 +147,7 @@ public:
// The number of tracker request command currently in the command queue.
int trackers;
int trackerNumTry;
+ Time announceInterval;
// tracker request
AnnounceList announceList;
public:
@@ -297,6 +302,18 @@ public:
void setHalt(bool 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 {
SINGLE,
diff --git a/src/TrackerUpdateCommand.cc b/src/TrackerUpdateCommand.cc
index f32c1238..1fdebc96 100644
--- a/src/TrackerUpdateCommand.cc
+++ b/src/TrackerUpdateCommand.cc
@@ -34,15 +34,13 @@
/* copyright --> */
#include "TrackerUpdateCommand.h"
#include "LogFactory.h"
-#include "MetaFileUtil.h"
#include "DlAbortEx.h"
#include "message.h"
#include "PeerInitiateConnectionCommand.h"
#include "SleepCommand.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();
}
@@ -53,7 +51,7 @@ bool TrackerUpdateCommand::prepareForRetry() {
return false;
}
-char* TrackerUpdateCommand::getTrackerResponse(int& trackerResponseLength) {
+char* TrackerUpdateCommand::getTrackerResponse(size_t& trackerResponseLength) {
int maxBufLength = 2048;
char* buf = new char[maxBufLength];
int bufLength = 0;
@@ -86,77 +84,24 @@ bool TrackerUpdateCommand::execute() {
return prepareForRetry();
}
char* trackerResponse = NULL;
- int trackerResponseLength = 0;
+ size_t trackerResponseLength = 0;
try {
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->connections < MIN_PEERS) {
- PeerHandle peer = e->torrentMan->getPeer();
- int newCuid = e->torrentMan->getNewCuid();
- peer->cuid = newCuid;
- PeerInitiateConnectionCommand* command =
- new PeerInitiateConnectionCommand(newCuid, peer, e);
- e->commands.push_back(command);
- logger->debug("CUID#%d - Adding new command CUID#%d", cuid, newCuid);
- }
- }
- if(!peersEntry) {
- logger->info("CUID#%d - No peer list received.", cuid);
+ e->torrentMan->processAnnounceResponse(trackerResponse,
+ trackerResponseLength);
+ while(e->torrentMan->needMorePeerConnection()) {
+ PeerHandle peer = e->torrentMan->getPeer();
+ int newCuid = e->torrentMan->getNewCuid();
+ peer->cuid = newCuid;
+ PeerInitiateConnectionCommand* command =
+ new PeerInitiateConnectionCommand(newCuid, peer, e);
+ e->commands.push_back(command);
+ logger->debug("CUID#%d - Adding new command CUID#%d", cuid, newCuid);
}
- e->torrentMan->announceList.announceSuccess();
- e->torrentMan->trackers = 0;
+ e->torrentMan->announceSuccess();
+ e->torrentMan->resetAnnounce();
e->segmentMan->init();
} catch(Exception* err) {
logger->error("CUID#%d - Error occurred while processing tracker response.", cuid, err);
diff --git a/src/TrackerUpdateCommand.h b/src/TrackerUpdateCommand.h
index 0d0de5a5..a4a0ad10 100644
--- a/src/TrackerUpdateCommand.h
+++ b/src/TrackerUpdateCommand.h
@@ -44,7 +44,7 @@ private:
TorrentDownloadEngine* e;
const Logger* logger;
bool prepareForRetry();
- char* getTrackerResponse(int& trackerResponseLength);
+ char* getTrackerResponse(size_t& trackerResponseLength);
public:
TrackerUpdateCommand(int cuid, TorrentDownloadEngine* e);
virtual ~TrackerUpdateCommand();
diff --git a/src/TrackerWatcherCommand.cc b/src/TrackerWatcherCommand.cc
index be7ed234..cea9a914 100644
--- a/src/TrackerWatcherCommand.cc
+++ b/src/TrackerWatcherCommand.cc
@@ -39,103 +39,48 @@
#include "prefs.h"
TrackerWatcherCommand::TrackerWatcherCommand(int cuid,
- TorrentDownloadEngine* e,
- int interval):
- Command(cuid), e(e), interval(interval) {
- // to force requesting to a tracker first time.
- checkPoint.setTimeInSec(0);
+ TorrentDownloadEngine* e):
+ Command(cuid), e(e) {
}
TrackerWatcherCommand::~TrackerWatcherCommand() {}
+
bool TrackerWatcherCommand::execute() {
+ if(e->torrentMan->isHalt() &&
+ e->segmentMan->errors > 0 && e->torrentMan->isAllAnnounceFailed() ||
+ e->torrentMan->noMoreAnnounce()) {
+ return true;
+ }
+ Command* command = createCommand();
+ if(command) {
+ e->commands.push_back(command);
+ }
+ e->commands.push_back(this);
+ return false;
+}
+
+Command* TrackerWatcherCommand::createCommand() {
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();
+ if(e->torrentMan->isAnnounceReady()) {
+ command = createRequestCommand(e->torrentMan->getAnnounceUrl());
+ e->torrentMan->announceStart(); // inside it, trackers++.
} 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->torrentMan->announceFailure(); // inside it, 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 {
+ if(e->torrentMan->isAllAnnounceFailed()) {
+ e->torrentMan->resetAnnounce();
// sleep a few seconds.
command =
new SleepCommand(cuid, e,
- createRequestCommand(),
+ createRequestCommand(e->torrentMan->getAnnounceUrl()),
e->option->getAsInt(PREF_RETRY_WAIT));
}
}
-
- if(command) {
- e->commands.push_back(command);
- e->torrentMan->trackers++;
- }
- // updates interval with newest minInterval
- interval = e->torrentMan->minInterval;
- e->commands.push_back(this);
- return false;
+ return command;
}
-Command* TrackerWatcherCommand::createRequestCommand() {
- int numWant = 50;
- if(e->torrentMan->connections >= MIN_PEERS || e->torrentMan->isHalt()) {
- numWant = 0;
- }
- string url = e->torrentMan->announceList.getAnnounce()+"?"+
- "info_hash="+Util::torrentUrlencode(e->torrentMan->getInfoHash(), 20)+"&"+
- "peer_id="+e->torrentMan->peerId+"&"+
- "port="+Util::itos(e->torrentMan->getPort())+"&"+
- "uploaded="+Util::llitos(e->torrentMan->getSessionUploadLength())+"&"+
- "downloaded="+Util::llitos(e->torrentMan->getSessionDownloadLength())+"&"+
- "left="+(e->torrentMan->getTotalLength()-e->torrentMan->getDownloadLength() <= 0
- ? "0" : Util::llitos(e->torrentMan->getTotalLength()-e->torrentMan->getDownloadLength()))+"&"+
- "compact=1"+"&"+
- "key="+e->torrentMan->key+"&"+
- "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;
- }
+Command* TrackerWatcherCommand::createRequestCommand(const string& url) {
RequestHandle req;
req->setUrl(url);
req->isTorrent = true;
diff --git a/src/TrackerWatcherCommand.h b/src/TrackerWatcherCommand.h
index 03d79c94..17708d1f 100644
--- a/src/TrackerWatcherCommand.h
+++ b/src/TrackerWatcherCommand.h
@@ -37,19 +37,22 @@
#include "Command.h"
#include "TorrentDownloadEngine.h"
-#include "TimeA2.h"
class TrackerWatcherCommand : public Command {
private:
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:
- TrackerWatcherCommand(int cuid, TorrentDownloadEngine* e, int interval);
+ TrackerWatcherCommand(int cuid, TorrentDownloadEngine* e);
~TrackerWatcherCommand();
+ Command* createCommand();
+
bool execute();
};