/* */ #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 "LogFactory.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" #include "fmt.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_->setRefreshInterval(0); e_->addCommand(this); return false; } } if(btAnnounce_->noMoreAnnounce()) { A2_LOG_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(); A2_LOG_DEBUG("added tracker request command"); } catch(RecoverableException& ex) { A2_LOG_ERROR_EX(EX_EXCEPTION_CAUGHT, ex); } } } else if(trackerRequestGroup_->downloadFinished()){ try { std::string trackerResponse = getTrackerResponse(trackerRequestGroup_); processTrackerResponse(trackerResponse); btAnnounce_->announceSuccess(); btAnnounce_->resetAnnounce(); } catch(RecoverableException& ex) { A2_LOG_ERROR_EX(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); A2_LOG_DEBUG(fmt("CUID#%lld - Adding new command CUID#%lld", getCuid(), peer->usedBy())); } } 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