/* */ #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" 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 ""; } unsigned int numWant = 50; if(!btRuntime->lessThanEqMinPeer() || 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 += std::string("&")+"port="+Util::uitos(btRuntime->getListenPort()); } std::string event = announceList.getEventString(); if(!event.empty()) { url += std::string("&")+"event="+event; } if(!trackerId.empty()) { url += std::string("&")+"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("failure reason")); if(failureReasonData) { throw DlAbortEx (StringFormat(EX_TRACKER_FAILURE, failureReasonData->toString().c_str()).str()); } const Data* warningMessageData = dynamic_cast(response->get("warning message")); if(warningMessageData) { logger->warn(MSG_TRACKER_WARNING_MESSAGE, warningMessageData->toString().c_str()); } const Data* trackerIdData = dynamic_cast(response->get("tracker id")); if(trackerIdData) { trackerId = trackerIdData->toString(); logger->debug("Tracker ID:%s", trackerId.c_str()); } const Data* intervalData = dynamic_cast(response->get("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("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; } const Data* completeData = dynamic_cast(response->get("complete")); if(completeData) { complete = completeData->toInt(); logger->debug("Complete:%d", complete); } const Data* incompleteData = dynamic_cast(response->get("incomplete")); if(incompleteData) { incomplete = incompleteData->toInt(); logger->debug("Incomplete:%d", incomplete); } const MetaEntry* peersEntry = response->get("peers"); if(peersEntry && !btRuntime->isHalt() && btRuntime->lessThanMinPeer()) { DelegatingPeerListProcessor proc; Peers peers = proc.extractPeer(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; } } // namespace aria2