From 597e1a5c1b10aa3668f91bcae02a864dcd0c045b Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Mon, 1 Apr 2013 00:12:27 +0900 Subject: Implement simple Happy Eyeballs for HTTP/FTP downloads --- src/BackupIPv4ConnectCommand.cc | 140 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 src/BackupIPv4ConnectCommand.cc (limited to 'src/BackupIPv4ConnectCommand.cc') diff --git a/src/BackupIPv4ConnectCommand.cc b/src/BackupIPv4ConnectCommand.cc new file mode 100644 index 00000000..9ca2081b --- /dev/null +++ b/src/BackupIPv4ConnectCommand.cc @@ -0,0 +1,140 @@ +/* */ +#include "BackupIPv4ConnectCommand.h" +#include "RequestGroup.h" +#include "DownloadEngine.h" +#include "SocketCore.h" +#include "wallclock.h" +#include "RecoverableException.h" +#include "fmt.h" +#include "LogFactory.h" +#include "prefs.h" +#include "Option.h" + +namespace aria2 { + +BackupConnectInfo::BackupConnectInfo() + : cancel(false) +{} + +BackupIPv4ConnectCommand::BackupIPv4ConnectCommand +(cuid_t cuid, const std::string& ipaddr, uint16_t port, + const SharedHandle& info, Command* mainCommand, + RequestGroup* requestGroup, DownloadEngine* e) +: Command(cuid), + ipaddr_(ipaddr), + port_(port), + info_(info), + mainCommand_(mainCommand), + requestGroup_(requestGroup), + e_(e), + startTime_(global::wallclock()), + timeoutCheck_(global::wallclock()), + timeout_(requestGroup_->getOption()->getAsInt(PREF_CONNECT_TIMEOUT)) +{ + requestGroup_->increaseStreamCommand(); + requestGroup_->increaseNumCommand(); +} + +BackupIPv4ConnectCommand::~BackupIPv4ConnectCommand() +{ + requestGroup_->decreaseNumCommand(); + requestGroup_->decreaseStreamCommand(); + if(socket_) { + e_->deleteSocketForWriteCheck(socket_, this); + } +} + +bool BackupIPv4ConnectCommand::execute() +{ + bool retval = false; + if(requestGroup_->downloadFinished() || requestGroup_->isHaltRequested()) { + retval = true; + } else if(info_->cancel) { + A2_LOG_INFO(fmt("CUID#%"PRId64" - Backup connection canceled", getCuid())); + retval = true; + } else if(socket_) { + if(writeEventEnabled()) { + try { + std::string error = socket_->getSocketError(); + if(error.empty()) { + A2_LOG_INFO(fmt("CUID#%"PRId64" - Backup connection to %s " + "established", getCuid(), ipaddr_.c_str())); + info_->ipaddr = ipaddr_; + e_->deleteSocketForWriteCheck(socket_, this); + info_->socket.swap(socket_); + mainCommand_->setStatus(STATUS_ONESHOT_REALTIME); + e_->setNoWait(true); + retval = true; + } else { + A2_LOG_INFO(fmt("CUID#%"PRId64" - Backup connection failed: %s", + getCuid(), error.c_str())); + retval = true; + } + } catch(RecoverableException& e) { + A2_LOG_INFO_EX(fmt("CUID#%"PRId64" - Backup connection failed", + getCuid()), e); + retval = true; + } + } + } else if(!socket_) { + // TODO Although we check 300ms initial timeout as described in + // RFC 6555, the interval will be much longer and around 1 second + // due to the refresh interval mechanism in DownloadEngine. + if(startTime_.differenceInMillis(global::wallclock()) >= 300) { + socket_.reset(new SocketCore()); + try { + socket_->establishConnection(ipaddr_, port_); + e_->addSocketForWriteCheck(socket_, this); + timeoutCheck_ = global::wallclock(); + } catch(RecoverableException& e) { + A2_LOG_INFO_EX(fmt("CUID#%"PRId64" - Backup connection failed", + getCuid()), e); + socket_.reset(); + retval = true; + } + } + } else if(timeoutCheck_.difference(global::wallclock()) >= timeout_) { + A2_LOG_INFO(fmt("CUID#%"PRId64" - Backup connection command timeout", + getCuid())); + retval = true; + } + if(!retval) { + e_->addCommand(this); + } + return retval; +} + +} // namespace aria2 -- cgit