/* */ #include "TrackerWatcherCommand.h" #include #include "DownloadEngine.h" #include "BtContext.h" #include "BtAnnounce.h" #include "BtRuntime.h" #include "PieceStorage.h" #include "PeerStorage.h" #include "Peer.h" #include "prefs.h" #include "message.h" #include "SingleFileDownloadContext.h" #include "ByteArrayDiskWriterFactory.h" #include "RecoverableException.h" #include "PeerInitiateConnectionCommand.h" #include "DiskAdaptor.h" #include "FileEntry.h" #include "RequestGroup.h" #include "Option.h" #include "DlAbortEx.h" #include "Logger.h" #include "A2STR.h" #include "SocketCore.h" #include "Request.h" #include "AnnounceTier.h" namespace aria2 { TrackerWatcherCommand::TrackerWatcherCommand(int32_t cuid, RequestGroup* requestGroup, DownloadEngine* e, const BtContextHandle& btContext): Command(cuid), _requestGroup(requestGroup), e(e), _btContext(btContext) { _requestGroup->increaseNumCommand(); } TrackerWatcherCommand::~TrackerWatcherCommand() { _requestGroup->decreaseNumCommand(); } bool TrackerWatcherCommand::execute() { if(_requestGroup->isForceHaltRequested()) { if(_trackerRequestGroup.isNull()) { return true; } else if(_trackerRequestGroup->getNumCommand() == 0 || _trackerRequestGroup->downloadFinished()) { return true; } else { _trackerRequestGroup->setForceHaltRequested(true); return false; } } if(_btAnnounce->noMoreAnnounce()) { logger->debug("no more announce"); return true; } if(_trackerRequestGroup.isNull()) { _trackerRequestGroup = createAnnounce(); if(!_trackerRequestGroup.isNull()) { std::deque commands; _trackerRequestGroup->createInitialCommand(commands, e, Request::METHOD_GET); e->addCommand(commands); logger->debug("added tracker request command"); } } else if(_trackerRequestGroup->downloadFinished()){ try { std::string trackerResponse = getTrackerResponse(_trackerRequestGroup); processTrackerResponse(trackerResponse); _btAnnounce->announceSuccess(); _btAnnounce->resetAnnounce(); } catch(RecoverableException& ex) { logger->error(EX_EXCEPTION_CAUGHT, ex); _btAnnounce->announceFailure(); if(_btAnnounce->isAllAnnounceFailed()) { _btAnnounce->resetAnnounce(); } } _trackerRequestGroup.reset(); } else if(_trackerRequestGroup->getNumCommand() == 0){ // handle errors here _btAnnounce->announceFailure(); // inside it, trackers = 0. _trackerRequestGroup.reset(); if(_btAnnounce->isAllAnnounceFailed()) { _btAnnounce->resetAnnounce(); } } e->commands.push_back(this); return false; } std::string TrackerWatcherCommand::getTrackerResponse (const RequestGroupHandle& requestGroup) { std::stringstream strm; unsigned char data[2048]; requestGroup->getPieceStorage()->getDiskAdaptor()->openFile(); while(1) { ssize_t dataLength = requestGroup->getPieceStorage()-> getDiskAdaptor()->readData(data, sizeof(data), strm.tellp()); if(dataLength == 0) { break; } strm.write(reinterpret_cast(data), dataLength); } return strm.str(); } // TODO we have to deal with the exception thrown By BtAnnounce void TrackerWatcherCommand::processTrackerResponse (const std::string& trackerResponse) { _btAnnounce->processAnnounceResponse (reinterpret_cast(trackerResponse.c_str()), trackerResponse.size()); while(!_btRuntime->isHalt() && _btRuntime->lessThanMinPeers()) { PeerHandle peer = _peerStorage->getUnusedPeer(); if(peer.isNull()) { break; } peer->usedBy(e->newCUID()); PeerInitiateConnectionCommand* command = new PeerInitiateConnectionCommand(peer->usedBy(), _requestGroup, peer, e, _btContext, _btRuntime); command->setPeerStorage(_peerStorage); command->setPieceStorage(_pieceStorage); e->commands.push_back(command); logger->debug("CUID#%d - Adding new command CUID#%d", cuid, peer->usedBy()); } } RequestGroupHandle TrackerWatcherCommand::createAnnounce() { RequestGroupHandle rg; if(_btAnnounce->isAnnounceReady()) { rg = createRequestGroup(_btAnnounce->getAnnounceUrl()); _btAnnounce->announceStart(); // inside it, trackers++. } return rg; } static bool backupTrackerIsAvailable (const std::deque >& announceTiers) { if(announceTiers.size() >= 2) { return true; } if(announceTiers.empty()) { return false; } if(announceTiers[0]->urls.size() >= 2) { return true; } else { return false; } } RequestGroupHandle TrackerWatcherCommand::createRequestGroup(const std::string& uri) { std::deque uris; uris.push_back(uri); RequestGroupHandle rg(new RequestGroup(getOption(), uris)); // If backup tracker is available, only try 2 times for each tracker // and if they all fails, then try next one. if(backupTrackerIsAvailable(_btContext->getAnnounceTiers())) { logger->debug("This is multi-tracker announce."); rg->setMaxTries(2); } else { logger->debug("This is single-tracker announce."); rg->setMaxTries(5); } static const std::string TRACKER_ANNOUNCE_FILE("[tracker.announce]"); SingleFileDownloadContextHandle dctx (new SingleFileDownloadContext(getOption()->getAsInt(PREF_SEGMENT_SIZE), 0, A2STR::NIL, TRACKER_ANNOUNCE_FILE)); dctx->setDir(A2STR::NIL); rg->setDownloadContext(dctx); SharedHandle dwf(new ByteArrayDiskWriterFactory()); rg->setDiskWriterFactory(dwf); rg->setFileAllocationEnabled(false); rg->setPreLocalFileCheckEnabled(false); logger->info("Creating tracker request group GID#%d", rg->getGID()); return rg; } void TrackerWatcherCommand::setBtRuntime (const SharedHandle& btRuntime) { _btRuntime = btRuntime; } void TrackerWatcherCommand::setPeerStorage (const SharedHandle& peerStorage) { _peerStorage = peerStorage; } void TrackerWatcherCommand::setPieceStorage (const SharedHandle& pieceStorage) { _pieceStorage = pieceStorage; } void TrackerWatcherCommand::setBtAnnounce (const SharedHandle& btAnnounce) { _btAnnounce = btAnnounce; } const SharedHandle