/* */ #include "NameResolveCommand.h" #include "DownloadEngine.h" #include "NameResolver.h" #include "prefs.h" #include "message.h" #include "util.h" #include "Option.h" #include "RequestGroupMan.h" #include "Logger.h" #include "LogFactory.h" #include "fmt.h" #include "UDPTrackerRequest.h" #include "UDPTrackerClient.h" #include "BtRegistry.h" #ifdef ENABLE_ASYNC_DNS #include "AsyncNameResolverMan.h" #endif // ENABLE_ASYNC_DNS namespace aria2 { NameResolveCommand::NameResolveCommand (cuid_t cuid, DownloadEngine* e, const SharedHandle& req) : Command(cuid), e_(e), #ifdef ENABLE_ASYNC_DNS asyncNameResolverMan_(new AsyncNameResolverMan()), #endif // ENABLE_ASYNC_DNS req_(req) { #ifdef ENABLE_ASYNC_DNS configureAsyncNameResolverMan(asyncNameResolverMan_.get(), e_->getOption()); // Currently we only utilize IPv4 DHT for UDP tracker asyncNameResolverMan_->setIPv6(false); #endif // ENABLE_ASYNC_DNS setStatus(Command::STATUS_ONESHOT_REALTIME); } NameResolveCommand::~NameResolveCommand() { #ifdef ENABLE_ASYNC_DNS asyncNameResolverMan_->disableNameResolverCheck(e_, this); #endif // ENABLE_ASYNC_DNS } bool NameResolveCommand::execute() { // This is UDP tracker specific, but we need to keep this command // alive until force shutdown is // commencing. RequestGroupMan::downloadFinished() is useless here // at the moment. if(e_->isForceHaltRequested()) { onShutdown(); return true; } const std::string& hostname = req_->remoteAddr; std::vector res; if(util::isNumericHost(hostname)) { res.push_back(hostname); } else { #ifdef ENABLE_ASYNC_DNS if(e_->getOption()->getAsBool(PREF_ASYNC_DNS)) { if(resolveHostname(res, hostname) == 0) { e_->addCommand(this); return false; } } else #endif // ENABLE_ASYNC_DNS { NameResolver resolver; resolver.setSocktype(SOCK_DGRAM); try { resolver.resolve(res, hostname); } catch(RecoverableException& e) { A2_LOG_ERROR_EX(EX_EXCEPTION_CAUGHT, e); } } } if(res.empty()) { onFailure(); } else { onSuccess(res, e_); } return true; } void NameResolveCommand::onShutdown() { req_->state = UDPT_STA_COMPLETE; req_->error = UDPT_ERR_SHUTDOWN; } void NameResolveCommand::onFailure() { req_->state = UDPT_STA_COMPLETE; req_->error = UDPT_ERR_NETWORK; } void NameResolveCommand::onSuccess (const std::vector& addrs, DownloadEngine* e) { req_->remoteAddr = addrs[0]; e->getBtRegistry()->getUDPTrackerClient()->addRequest(req_); } #ifdef ENABLE_ASYNC_DNS int NameResolveCommand::resolveHostname (std::vector& res, const std::string& hostname) { if(!asyncNameResolverMan_->started()) { asyncNameResolverMan_->startAsync(hostname, e_, this); return 0; } else { switch(asyncNameResolverMan_->getStatus()) { case -1: A2_LOG_INFO (fmt(MSG_NAME_RESOLUTION_FAILED, getCuid(), hostname.c_str(), asyncNameResolverMan_->getLastError().c_str())); return -1; case 0: return 0; case 1: asyncNameResolverMan_->getResolvedAddress(res); if(res.empty()) { A2_LOG_INFO (fmt(MSG_NAME_RESOLUTION_FAILED, getCuid(), hostname.c_str(), "No address returned")); return -1; } else { A2_LOG_INFO(fmt(MSG_NAME_RESOLUTION_COMPLETE, getCuid(), hostname.c_str(), res.front().c_str())); return 1; } } } // Unreachable return 0; } #endif // ENABLE_ASYNC_DNS } // namespace aria2