/* */ #include "DefaultBtAnnounce.h" #include "BtRegistry.h" #include "LogFactory.h" #include "Logger.h" #include "MetaFileUtil.h" #include "Dictionary.h" #include "List.h" #include "Data.h" #include "DelegatingPeerListProcessor.h" #include "Util.h" #include "prefs.h" #include "DlAbortEx.h" #include "message.h" #include "SimpleRandomizer.h" #include "BtContext.h" #include "PieceStorage.h" #include "BtRuntime.h" #include "PeerStorage.h" #include "Peer.h" #include "Option.h" #include "StringFormat.h" #include "A2STR.h" namespace aria2 { DefaultBtAnnounce::DefaultBtAnnounce(const BtContextHandle& btContext, const Option* option): btContext(btContext), trackers(0), interval(DEFAULT_ANNOUNCE_INTERVAL), minInterval(DEFAULT_ANNOUNCE_INTERVAL), complete(0), incomplete(0), announceList(btContext->getAnnounceTiers()), option(option), logger(LogFactory::getInstance()), _randomizer(SimpleRandomizer::getInstance()), btRuntime(BT_RUNTIME(btContext)), pieceStorage(PIECE_STORAGE(btContext)), peerStorage(PEER_STORAGE(btContext)) { prevAnnounceTime.setTimeInSec(0); generateKey(); } DefaultBtAnnounce::~DefaultBtAnnounce() { } void DefaultBtAnnounce::generateKey() { key = Util::randomAlpha(8, _randomizer); } bool DefaultBtAnnounce::isDefaultAnnounceReady() { return (trackers == 0 && prevAnnounceTime.elapsed(minInterval) && !announceList.allTiersFailed()); } bool DefaultBtAnnounce::isStoppedAnnounceReady() { return (trackers == 0 && btRuntime->isHalt() && announceList.countStoppedAllowedTier()); } bool DefaultBtAnnounce::isCompletedAnnounceReady() { return (trackers == 0 && pieceStorage->allDownloadFinished() && announceList.countCompletedAllowedTier()); } bool DefaultBtAnnounce::isAnnounceReady() { return isStoppedAnnounceReady() || isCompletedAnnounceReady() || isDefaultAnnounceReady(); } std::string DefaultBtAnnounce::getAnnounceUrl() { if(isStoppedAnnounceReady()) { if(!announceList.currentTierAcceptsStoppedEvent()) { announceList.moveToStoppedAllowedTier(); } announceList.setEvent(AnnounceTier::STOPPED); } else if(isCompletedAnnounceReady()) { if(!announceList.currentTierAcceptsCompletedEvent()) { 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(pieceStorage->allDownloadFinished() && announceList.getEvent() == AnnounceTier::STARTED) { announceList.setEvent(AnnounceTier::STARTED_AFTER_COMPLETION); } } else { return A2STR::NIL; } unsigned int numWant = 50; if(!btRuntime->lessThanMinPeers() || btRuntime->isHalt()) { numWant = 0; } TransferStat stat = peerStorage->calculateStat(); uint64_t left = pieceStorage->getTotalLength()-pieceStorage->getCompletedLength(); if(left < 0) { left = 0; } std::string url = announceList.getAnnounce()+ "?info_hash="+Util::torrentUrlencode(btContext->getInfoHash(), btContext->getInfoHashLength())+ "&peer_id="+Util::torrentUrlencode(btContext->getPeerId(), 20)+ "&uploaded="+Util::uitos(stat.getSessionUploadLength())+ "&downloaded="+Util::uitos(stat.getSessionDownloadLength())+ "&left="+Util::uitos(left)+ "&compact=1"+ "&key="+key+ "&numwant="+Util::uitos(numWant)+ "&no_peer_id=1"; if(btRuntime->getListenPort() > 0) { url += "&port="+Util::uitos(btRuntime->getListenPort()); } std::string event = announceList.getEventString(); if(!event.empty()) { url += "&event="+event; } if(!trackerId.empty()) { url += "&trackerid="+Util::torrentUrlencode(trackerId); } if(option->getAsBool(PREF_BT_REQUIRE_CRYPTO)) { url += "&requirecrypto=1"; } else { url += "&supportcrypto=1"; } return url; } void DefaultBtAnnounce::announceStart() { trackers++; } void DefaultBtAnnounce::announceSuccess() { trackers = 0; announceList.announceSuccess(); } void DefaultBtAnnounce::announceFailure() { trackers = 0; announceList.announceFailure(); } bool DefaultBtAnnounce::isAllAnnounceFailed() { return announceList.allTiersFailed(); } void DefaultBtAnnounce::resetAnnounce() { prevAnnounceTime.reset(); announceList.resetTier(); } void DefaultBtAnnounce::processAnnounceResponse(const unsigned char* trackerResponse, size_t trackerResponseLength) { SharedHandle entry(MetaFileUtil::bdecoding(trackerResponse, trackerResponseLength)); const Dictionary* response = dynamic_cast(entry.get()); if(!response) { throw DlAbortEx(MSG_NULL_TRACKER_RESPONSE); } const Data* failureReasonData = dynamic_cast(response->get(BtAnnounce::FAILURE_REASON)); if(failureReasonData) { throw DlAbortEx (StringFormat(EX_TRACKER_FAILURE, failureReasonData->toString().c_str()).str()); } const Data* warningMessageData = dynamic_cast(response->get(BtAnnounce::WARNING_MESSAGE)); if(warningMessageData) { logger->warn(MSG_TRACKER_WARNING_MESSAGE, warningMessageData->toString().c_str()); } const Data* trackerIdData = dynamic_cast(response->get(BtAnnounce::TRACKER_ID)); if(trackerIdData) { trackerId = trackerIdData->toString(); logger->debug("Tracker ID:%s", trackerId.c_str()); } const Data* intervalData = dynamic_cast(response->get(BtAnnounce::INTERVAL)); if(intervalData) { time_t t = intervalData->toInt(); if(t > 0) { interval = intervalData->toInt(); logger->debug("Interval:%d", interval); } } const Data* minIntervalData = dynamic_cast(response->get(BtAnnounce::MIN_INTERVAL)); if(minIntervalData) { time_t t = minIntervalData->toInt(); if(t > 0) { minInterval = minIntervalData->toInt(); logger->debug("Min interval:%d", minInterval); } if(minInterval > interval) { minInterval = interval; } } else { // Use interval as a minInterval if minInterval is not supplied. minInterval = interval; } const Data* completeData = dynamic_cast(response->get(BtAnnounce::COMPLETE)); if(completeData) { complete = completeData->toInt(); logger->debug("Complete:%d", complete); } const Data* incompleteData = dynamic_cast(response->get(BtAnnounce::INCOMPLETE)); if(incompleteData) { incomplete = incompleteData->toInt(); logger->debug("Incomplete:%d", incomplete); } const MetaEntry* peersEntry = response->get(BtAnnounce::PEERS); if(peersEntry && !btRuntime->isHalt() && btRuntime->lessThanMinPeers()) { DelegatingPeerListProcessor proc; std::deque > peers; proc.extractPeer(peers, peersEntry); peerStorage->addPeer(peers); } if(!peersEntry) { logger->info(MSG_NO_PEER_LIST_RECEIVED); } } bool DefaultBtAnnounce::noMoreAnnounce() { return (trackers == 0 && btRuntime->isHalt() && !announceList.countStoppedAllowedTier()); } void DefaultBtAnnounce::shuffleAnnounce() { announceList.shuffle(); } void DefaultBtAnnounce::setRandomizer(const RandomizerHandle& randomizer) { _randomizer = randomizer; } void DefaultBtAnnounce::setBtRuntime(const BtRuntimeHandle& btRuntime) { this->btRuntime = btRuntime; } BtRuntimeHandle DefaultBtAnnounce::getBtRuntime() const { return btRuntime; } void DefaultBtAnnounce::setPieceStorage(const PieceStorageHandle& pieceStorage) { this->pieceStorage = pieceStorage; } PieceStorageHandle DefaultBtAnnounce::getPieceStorage() const { return pieceStorage; } void DefaultBtAnnounce::setPeerStorage(const PeerStorageHandle& peerStorage) { this->peerStorage = peerStorage; } PeerStorageHandle DefaultBtAnnounce::getPeerStorage() const { return peerStorage; } void DefaultBtAnnounce::overrideMinInterval(time_t interval) { minInterval = interval; } } // namespace aria2