diff options
| author | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2006-10-20 13:20:50 +0000 |
|---|---|---|
| committer | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2006-10-20 13:20:50 +0000 |
| commit | b8737b0e7c92fb4a5b1c8b6173663381aacca40c (patch) | |
| tree | 0d5b0f79eb0bfbe5cda58cce30f3523c803f2d5c /src | |
| parent | c0fd1fff2a6d78d3157790bbef6f98d54f31d0fc (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.cc | 3 | ||||
| -rw-r--r-- | src/TorrentMan.cc | 158 | ||||
| -rw-r--r-- | src/TorrentMan.h | 17 | ||||
| -rw-r--r-- | src/TrackerUpdateCommand.cc | 85 | ||||
| -rw-r--r-- | src/TrackerUpdateCommand.h | 2 | ||||
| -rw-r--r-- | src/TrackerWatcherCommand.cc | 107 | ||||
| -rw-r--r-- | src/TrackerWatcherCommand.h | 13 |
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(); }; |
