/* */ #include "TrackerWatcherCommand.h" #include #include "DownloadEngine.h" #include "BtAnnounce.h" #include "BtRuntime.h" #include "PieceStorage.h" #include "PeerStorage.h" #include "Peer.h" #include "prefs.h" #include "message.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" #include "DownloadContext.h" #include "bittorrent_helper.h" #include "a2functional.h" #include "util.h" namespace aria2 { TrackerWatcherCommand::TrackerWatcherCommand (cuid_t cuid, RequestGroup* requestGroup, DownloadEngine* e): Command(cuid), requestGroup_(requestGroup), e_(e) { requestGroup_->increaseNumCommand(); } TrackerWatcherCommand::~TrackerWatcherCommand() { requestGroup_->decreaseNumCommand(); } bool TrackerWatcherCommand::execute() { if(requestGroup_->isForceHaltRequested()) { if(!trackerRequestGroup_) { return true; } else if(trackerRequestGroup_->getNumCommand() == 0 || trackerRequestGroup_->downloadFinished()) { return true; } else { trackerRequestGroup_->setForceHaltRequested(true); e_->addCommand(this); return false; } } if(btAnnounce_->noMoreAnnounce()) { if(getLogger()->debug()) { getLogger()->debug("no more announce"); } return true; } if(!trackerRequestGroup_) { trackerRequestGroup_ = createAnnounce(); if(trackerRequestGroup_) { try { std::vector* commands = new std::vector(); auto_delete_container > commandsDel(commands); trackerRequestGroup_->createInitialCommand(*commands, e_); e_->addCommand(*commands); commands->clear(); if(getLogger()->debug()) { getLogger()->debug("added tracker request command"); } } catch(RecoverableException& ex) { getLogger()->error(EX_EXCEPTION_CAUGHT, ex); } } } else if(trackerRequestGroup_->downloadFinished()){ try { std::string trackerResponse = getTrackerResponse(trackerRequestGroup_); processTrackerResponse(trackerResponse); btAnnounce_->announceSuccess(); btAnnounce_->resetAnnounce(); } catch(RecoverableException& ex) { getLogger()->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_->addCommand(this); return false; } std::string TrackerWatcherCommand::getTrackerResponse (const SharedHandle& 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()) { SharedHandle peer = peerStorage_->getUnusedPeer(); if(!peer) { break; } peer->usedBy(e_->newCUID()); PeerInitiateConnectionCommand* command = new PeerInitiateConnectionCommand (peer->usedBy(), requestGroup_, peer, e_, btRuntime_); command->setPeerStorage(peerStorage_); command->setPieceStorage(pieceStorage_); e_->addCommand(command); if(getLogger()->debug()) { getLogger()->debug("CUID#%s - Adding new command CUID#%s", util::itos(getCuid()).c_str(), util::itos(peer->usedBy()).c_str()); } } } SharedHandle TrackerWatcherCommand::createAnnounce() { SharedHandle rg; if(btAnnounce_->isAnnounceReady()) { rg = createRequestGroup(btAnnounce_->getAnnounceUrl()); btAnnounce_->announceStart(); // inside it, trackers++. } return rg; } namespace { bool backupTrackerIsAvailable (const SharedHandle& context) { SharedHandle torrentAttrs = bittorrent::getTorrentAttrs(context); if(torrentAttrs->announceList.size() >= 2) { return true; } if(torrentAttrs->announceList.empty()) { return false; } if(torrentAttrs->announceList[0].size() >= 2) { return true; } else { return false; } } } // namespace SharedHandle TrackerWatcherCommand::createRequestGroup(const std::string& uri) { std::vector uris; uris.push_back(uri); SharedHandle rg(new RequestGroup(getOption())); if(backupTrackerIsAvailable(requestGroup_->getDownloadContext())) { if(getLogger()->debug()) { getLogger()->debug("This is multi-tracker announce."); } } else { if(getLogger()->debug()) { getLogger()->debug("This is single-tracker announce."); } } rg->setNumConcurrentCommand(1); // If backup tracker is available, try 2 times for each tracker // and if they all fails, then try next one. rg->getOption()->put(PREF_MAX_TRIES, "2"); // TODO When dry-run mode becomes available in BitTorrent, set // PREF_DRY_RUN=false too. rg->getOption()->put(PREF_USE_HEAD, A2_V_FALSE); // Setting tracker timeouts rg->setTimeout(rg->getOption()->getAsInt(PREF_BT_TRACKER_TIMEOUT)); rg->getOption()->put(PREF_CONNECT_TIMEOUT, rg->getOption()->get(PREF_BT_TRACKER_CONNECT_TIMEOUT)); rg->getOption()->put(PREF_REUSE_URI, A2_V_FALSE); rg->getOption()->put(PREF_SELECT_LEAST_USED_HOST, A2_V_FALSE); static const std::string TRACKER_ANNOUNCE_FILE("[tracker.announce]"); SharedHandle dctx (new DownloadContext(getOption()->getAsInt(PREF_SEGMENT_SIZE), 0, TRACKER_ANNOUNCE_FILE)); dctx->setDir(A2STR::NIL); dctx->getFileEntries().front()->setUris(uris); rg->setDownloadContext(dctx); SharedHandle dwf(new ByteArrayDiskWriterFactory()); rg->setDiskWriterFactory(dwf); rg->setFileAllocationEnabled(false); rg->setPreLocalFileCheckEnabled(false); util::removeMetalinkContentTypes(rg); if(getLogger()->info()) { getLogger()->info("Creating tracker request group GID#%s", util::itos(rg->getGID()).c_str()); } 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