diff --git a/src/AbstractCommand.cc b/src/AbstractCommand.cc index 916e9fe8..8b311fcb 100644 --- a/src/AbstractCommand.cc +++ b/src/AbstractCommand.cc @@ -225,7 +225,7 @@ bool AbstractCommand::execute() { #ifdef ENABLE_ASYNC_DNS && !asyncNameResolverMan_->resolverChecked() #endif // ENABLE_ASYNC_DNS - )) { + ) || noCheck()) { checkPoint_ = global::wallclock(); if(getPieceStorage()) { if(!req_ || req_->getMaxPipelinedRequest() == 1 || diff --git a/src/AbstractCommand.h b/src/AbstractCommand.h index 53676077..d0749aa7 100644 --- a/src/AbstractCommand.h +++ b/src/AbstractCommand.h @@ -123,6 +123,11 @@ protected: return socket_; } + SharedHandle& getSocket() + { + return socket_; + } + void setSocket(const SharedHandle& s); void createSocket(); @@ -215,6 +220,13 @@ protected: } void checkSocketRecvBuffer(); + + // Returns true if the derived class wants to execute + // executeInternal() unconditionally + virtual bool noCheck() + { + return false; + } public: AbstractCommand (cuid_t cuid, const SharedHandle& req, diff --git a/src/AbstractProxyRequestCommand.cc b/src/AbstractProxyRequestCommand.cc index 22bce921..1f9fe1ba 100644 --- a/src/AbstractProxyRequestCommand.cc +++ b/src/AbstractProxyRequestCommand.cc @@ -44,6 +44,9 @@ #include "SocketCore.h" #include "DownloadContext.h" #include "SocketRecvBuffer.h" +#include "BackupIPv4ConnectCommand.h" +#include "fmt.h" +#include "LogFactory.h" namespace aria2 { @@ -67,16 +70,48 @@ AbstractProxyRequestCommand::AbstractProxyRequestCommand setWriteCheckSocket(getSocket()); } -AbstractProxyRequestCommand::~AbstractProxyRequestCommand() {} +AbstractProxyRequestCommand::~AbstractProxyRequestCommand() +{ + if(backupConnectionInfo_) { + backupConnectionInfo_->cancel = true; + } +} + +bool AbstractProxyRequestCommand::noCheck() { + return backupConnectionInfo_ && !backupConnectionInfo_->ipaddr.empty(); +} bool AbstractProxyRequestCommand::executeInternal() { //socket->setBlockingMode(); if(httpConnection_->sendBufferIsEmpty()) { + if(backupConnectionInfo_ && !backupConnectionInfo_->ipaddr.empty()) { + A2_LOG_INFO(fmt("CUID#%"PRId64" - Use backup connection address %s", + getCuid(), backupConnectionInfo_->ipaddr.c_str())); + getDownloadEngine()->markBadIPAddress + (getRequest()->getConnectedHostname(), + getRequest()->getConnectedAddr(), + getRequest()->getConnectedPort()); + + getRequest()->setConnectedAddrInfo(getRequest()->getConnectedHostname(), + backupConnectionInfo_->ipaddr, + getRequest()->getConnectedPort()); + + Command* c = createSelf(backupConnectionInfo_->socket); + c->setStatus(STATUS_ONESHOT_REALTIME); + getDownloadEngine()->setNoWait(true); + getDownloadEngine()->addCommand(c); + backupConnectionInfo_.reset(); + return true; + } if(!checkIfConnectionEstablished (getSocket(), getRequest()->getConnectedHostname(), getRequest()->getConnectedAddr(), getRequest()->getConnectedPort())) { return true; } + if(backupConnectionInfo_) { + backupConnectionInfo_->cancel = true; + backupConnectionInfo_.reset(); + } SharedHandle httpRequest(new HttpRequest()); httpRequest->setUserAgent(getOption()->get(PREF_USER_AGENT)); httpRequest->setRequest(getRequest()); @@ -96,4 +131,10 @@ bool AbstractProxyRequestCommand::executeInternal() { } } +void AbstractProxyRequestCommand::setBackupConnectInfo +(const SharedHandle& info) +{ + backupConnectionInfo_ = info; +} + } // namespace aria2 diff --git a/src/AbstractProxyRequestCommand.h b/src/AbstractProxyRequestCommand.h index 841ebf85..ed863e14 100644 --- a/src/AbstractProxyRequestCommand.h +++ b/src/AbstractProxyRequestCommand.h @@ -41,19 +41,28 @@ namespace aria2 { class HttpConnection; class SocketCore; +class BackupConnectInfo; class AbstractProxyRequestCommand : public AbstractCommand { private: SharedHandle proxyRequest_; SharedHandle httpConnection_; + + SharedHandle backupConnectionInfo_; protected: virtual bool executeInternal(); + virtual bool noCheck(); const SharedHandle& getHttpConnection() const { return httpConnection_; } + + const SharedHandle& getProxyRequest() const + { + return proxyRequest_; + } public: AbstractProxyRequestCommand(cuid_t cuid, const SharedHandle& req, @@ -66,6 +75,8 @@ public: virtual ~AbstractProxyRequestCommand(); virtual Command* getNextCommand() = 0; + virtual Command* createSelf(const SharedHandle& socket) = 0; + void setBackupConnectInfo(const SharedHandle& info); }; } // namespace aria2 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 diff --git a/src/BackupIPv4ConnectCommand.h b/src/BackupIPv4ConnectCommand.h new file mode 100644 index 00000000..de207bc1 --- /dev/null +++ b/src/BackupIPv4ConnectCommand.h @@ -0,0 +1,89 @@ +/* */ +#ifndef BACKUP_IPV4_CONNECT_COMMAND_H +#define BACKUP_IPV4_CONNECT_COMMAND_H + +#include "Command.h" + +#include + +#include "SharedHandle.h" +#include "TimerA2.h" + +namespace aria2 { + +class RequestGroup; +class DownloadEngine; +class SocketCore; + +// Used to communicate mainCommand and backup IPv4 connection command. +// When backup connection succeeds, ipaddr is filled with connected +// IPv4 address and socket is a socket connected to the ipaddr. If +// mainCommand wants to cancel backup connection command, cancel +// member becomes true. +struct BackupConnectInfo { + std::string ipaddr; + SharedHandle socket; + bool cancel; + BackupConnectInfo(); +}; + +// Make backup connection to IPv4 address. This is a simplest RFC 6555 +// "Happy Eyeballs" implementation. +class BackupIPv4ConnectCommand : public Command { +public: + BackupIPv4ConnectCommand(cuid_t cuid, + const std::string& ipaddr, uint16_t port, + const SharedHandle& info, + Command* mainCommand, + RequestGroup* requestGroup, DownloadEngine* e); + ~BackupIPv4ConnectCommand(); + virtual bool execute(); +private: + std::string ipaddr_; + uint16_t port_; + SharedHandle socket_; + SharedHandle info_; + Command* mainCommand_; + RequestGroup* requestGroup_; + DownloadEngine* e_; + Timer startTime_; + Timer timeoutCheck_; + time_t timeout_; +}; + +} // namespace aria2 + +#endif // BACKUP_IPV4_CONNECT_COMMAND_H diff --git a/src/FtpInitiateConnectionCommand.cc b/src/FtpInitiateConnectionCommand.cc index 374bfccb..1daf5e61 100644 --- a/src/FtpInitiateConnectionCommand.cc +++ b/src/FtpInitiateConnectionCommand.cc @@ -56,6 +56,7 @@ #include "AuthConfig.h" #include "fmt.h" #include "SocketRecvBuffer.h" +#include "BackupIPv4ConnectCommand.h" namespace aria2 { @@ -110,12 +111,22 @@ Command* FtpInitiateConnectionCommand::createNextCommand getRequestGroup(), hc, getDownloadEngine(), getSocket()); c->setProxyRequest(proxyRequest); + SharedHandle backupConnectInfo + = createBackupIPv4ConnectCommand(hostname, addr, port, c); + if(backupConnectInfo) { + c->setBackupConnectInfo(backupConnectInfo); + } command = c; } else if(proxyMethod == V_TUNNEL) { FtpTunnelRequestCommand* c = new FtpTunnelRequestCommand(getCuid(), getRequest(), getFileEntry(), getRequestGroup(), getDownloadEngine(), proxyRequest, getSocket()); + SharedHandle backupConnectInfo + = createBackupIPv4ConnectCommand(hostname, addr, port, c); + if(backupConnectInfo) { + c->setBackupConnectInfo(backupConnectInfo); + } command = c; } else { // TODO @@ -163,11 +174,16 @@ Command* FtpInitiateConnectionCommand::createNextCommand getCuid(), addr.c_str(), port)); createSocket(); getSocket()->establishConnection(addr, port); + getRequest()->setConnectedAddrInfo(hostname, addr, port); FtpNegotiationCommand* c = new FtpNegotiationCommand(getCuid(), getRequest(), getFileEntry(), getRequestGroup(), getDownloadEngine(), getSocket()); - getRequest()->setConnectedAddrInfo(hostname, addr, port); + SharedHandle backupConnectInfo + = createBackupIPv4ConnectCommand(hostname, addr, port, c); + if(backupConnectInfo) { + c->setBackupConnectInfo(backupConnectInfo); + } command = c; } else { // options contains "baseWorkingDir" diff --git a/src/FtpNegotiationCommand.cc b/src/FtpNegotiationCommand.cc index 03827b54..b21ff71f 100644 --- a/src/FtpNegotiationCommand.cc +++ b/src/FtpNegotiationCommand.cc @@ -74,6 +74,7 @@ #include "CheckIntegrityEntry.h" #include "error_code.h" #include "SocketRecvBuffer.h" +#include "BackupIPv4ConnectCommand.h" #ifdef ENABLE_MESSAGE_DIGEST # include "ChecksumCheckIntegrityEntry.h" #endif // ENABLE_MESSAGE_DIGEST @@ -105,7 +106,16 @@ FtpNegotiationCommand::FtpNegotiationCommand setWriteCheckSocket(getSocket()); } -FtpNegotiationCommand::~FtpNegotiationCommand() {} +FtpNegotiationCommand::~FtpNegotiationCommand() +{ + if(backupConnectionInfo_) { + backupConnectionInfo_->cancel = true; + } +} + +bool FtpNegotiationCommand::noCheck() { + return backupConnectionInfo_ && !backupConnectionInfo_->ipaddr.empty(); +} bool FtpNegotiationCommand::executeInternal() { while(processSequence(getSegments().front())); @@ -145,12 +155,38 @@ bool FtpNegotiationCommand::executeInternal() { } bool FtpNegotiationCommand::recvGreeting() { + if(backupConnectionInfo_ && !backupConnectionInfo_->ipaddr.empty()) { + A2_LOG_INFO(fmt("CUID#%"PRId64" - Use backup connection address %s", + getCuid(), backupConnectionInfo_->ipaddr.c_str())); + getDownloadEngine()->markBadIPAddress + (getRequest()->getConnectedHostname(), + getRequest()->getConnectedAddr(), + getRequest()->getConnectedPort()); + + getRequest()->setConnectedAddrInfo(getRequest()->getConnectedHostname(), + backupConnectionInfo_->ipaddr, + getRequest()->getConnectedPort()); + + FtpNegotiationCommand* c = + new FtpNegotiationCommand(getCuid(), getRequest(), getFileEntry(), + getRequestGroup(), getDownloadEngine(), + backupConnectionInfo_->socket); + c->setStatus(STATUS_ONESHOT_REALTIME); + getDownloadEngine()->setNoWait(true); + getDownloadEngine()->addCommand(c); + backupConnectionInfo_.reset(); + return true; + } if(!checkIfConnectionEstablished (getSocket(), getRequest()->getConnectedHostname(), getRequest()->getConnectedAddr(), getRequest()->getConnectedPort())) { sequence_ = SEQ_EXIT; return false; } + if(backupConnectionInfo_) { + backupConnectionInfo_->cancel = true; + backupConnectionInfo_.reset(); + } setTimeout(getRequestGroup()->getTimeout()); //socket->setBlockingMode(); disableWriteCheckSocket(); @@ -973,4 +1009,10 @@ void FtpNegotiationCommand::onDryRunFileFound() sequence_ = SEQ_HEAD_OK; } +void FtpNegotiationCommand::setBackupConnectInfo +(const SharedHandle& info) +{ + backupConnectionInfo_ = info; +} + } // namespace aria2 diff --git a/src/FtpNegotiationCommand.h b/src/FtpNegotiationCommand.h index 07e4c228..ebd79544 100644 --- a/src/FtpNegotiationCommand.h +++ b/src/FtpNegotiationCommand.h @@ -44,6 +44,7 @@ namespace aria2 { class FtpConnection; class SocketCore; class HttpConnection; +class BackupConnectInfo; class FtpNegotiationCommand : public AbstractCommand { public: @@ -153,8 +154,11 @@ private: std::string proxyAddr_; std::deque cwdDirs_; + + SharedHandle backupConnectionInfo_; protected: virtual bool executeInternal(); + virtual bool noCheck(); public: FtpNegotiationCommand(cuid_t cuid, const SharedHandle& req, @@ -165,6 +169,7 @@ public: Seq seq = SEQ_RECV_GREETING, const std::string& baseWorkingDir = "/"); virtual ~FtpNegotiationCommand(); + void setBackupConnectInfo(const SharedHandle& info); }; } // namespace aria2 diff --git a/src/FtpTunnelRequestCommand.cc b/src/FtpTunnelRequestCommand.cc index 2ca92895..c74a1665 100644 --- a/src/FtpTunnelRequestCommand.cc +++ b/src/FtpTunnelRequestCommand.cc @@ -63,4 +63,12 @@ Command* FtpTunnelRequestCommand::getNextCommand() getHttpConnection(), getDownloadEngine(), getSocket()); } +Command* FtpTunnelRequestCommand::createSelf +(const SharedHandle& socket) +{ + return new FtpTunnelRequestCommand(getCuid(), getRequest(), getFileEntry(), + getRequestGroup(), getDownloadEngine(), + getProxyRequest(), socket); +} + } // namespace aria2 diff --git a/src/FtpTunnelRequestCommand.h b/src/FtpTunnelRequestCommand.h index c22ff381..97b585cd 100644 --- a/src/FtpTunnelRequestCommand.h +++ b/src/FtpTunnelRequestCommand.h @@ -53,6 +53,8 @@ public: virtual ~FtpTunnelRequestCommand(); virtual Command* getNextCommand(); + + virtual Command* createSelf(const SharedHandle& socket); }; } // namespace aria2 diff --git a/src/HttpInitiateConnectionCommand.cc b/src/HttpInitiateConnectionCommand.cc index 794b1886..deb9c62d 100644 --- a/src/HttpInitiateConnectionCommand.cc +++ b/src/HttpInitiateConnectionCommand.cc @@ -51,6 +51,7 @@ #include "util.h" #include "fmt.h" #include "SocketRecvBuffer.h" +#include "BackupIPv4ConnectCommand.h" namespace aria2 { @@ -93,6 +94,11 @@ Command* HttpInitiateConnectionCommand::createNextCommand getDownloadEngine(), proxyRequest, getSocket()); + SharedHandle backupConnectionInfo + = createBackupIPv4ConnectCommand(hostname, addr, port, c); + if(backupConnectionInfo) { + c->setBackupConnectInfo(backupConnectionInfo); + } command = c; } else if(proxyMethod == V_GET) { SharedHandle socketRecvBuffer @@ -107,6 +113,11 @@ Command* HttpInitiateConnectionCommand::createNextCommand getDownloadEngine(), getSocket()); c->setProxyRequest(proxyRequest); + SharedHandle backupConnectionInfo + = createBackupIPv4ConnectCommand(hostname, addr, port, c); + if(backupConnectionInfo) { + c->setBackupConnectInfo(backupConnectionInfo); + } command = c; } else { // TODO @@ -131,6 +142,7 @@ Command* HttpInitiateConnectionCommand::createNextCommand command = c; } } else { + bool connectRequired = false; SharedHandle pooledSocket = getDownloadEngine()->popPooledSocket (resolvedAddresses, getRequest()->getPort()); @@ -141,6 +153,7 @@ Command* HttpInitiateConnectionCommand::createNextCommand getSocket()->establishConnection(addr, port); getRequest()->setConnectedAddrInfo(hostname, addr, port); + connectRequired = true; } else { setSocket(pooledSocket); setConnectedAddrInfo(getRequest(), hostname, pooledSocket); @@ -155,6 +168,14 @@ Command* HttpInitiateConnectionCommand::createNextCommand httpConnection, getDownloadEngine(), getSocket()); + if(connectRequired) { + SharedHandle backupConnectInfo + = createBackupIPv4ConnectCommand(hostname, addr, port, c); + if(backupConnectInfo) { + c->setBackupConnectInfo(backupConnectInfo); + } + } + command = c; } return command; diff --git a/src/HttpProxyRequestCommand.cc b/src/HttpProxyRequestCommand.cc index 410345ce..9be2a230 100644 --- a/src/HttpProxyRequestCommand.cc +++ b/src/HttpProxyRequestCommand.cc @@ -62,4 +62,16 @@ Command* HttpProxyRequestCommand::getNextCommand() getHttpConnection(), getDownloadEngine(), getSocket()); } +Command* HttpProxyRequestCommand::createSelf +(const SharedHandle& socket) +{ + return new HttpProxyRequestCommand(getCuid(), + getRequest(), + getFileEntry(), + getRequestGroup(), + getDownloadEngine(), + getProxyRequest(), + socket); +} + } // namespace aria2 diff --git a/src/HttpProxyRequestCommand.h b/src/HttpProxyRequestCommand.h index 60fd6648..15b50c31 100644 --- a/src/HttpProxyRequestCommand.h +++ b/src/HttpProxyRequestCommand.h @@ -53,6 +53,8 @@ public: virtual ~HttpProxyRequestCommand(); virtual Command* getNextCommand(); + + virtual Command* createSelf(const SharedHandle& socket); }; } // namespace aria2 diff --git a/src/HttpRequestCommand.cc b/src/HttpRequestCommand.cc index f393125f..6fc083c6 100644 --- a/src/HttpRequestCommand.cc +++ b/src/HttpRequestCommand.cc @@ -59,6 +59,7 @@ #include "LogFactory.h" #include "fmt.h" #include "SocketRecvBuffer.h" +#include "BackupIPv4ConnectCommand.h" namespace aria2 { @@ -79,7 +80,12 @@ HttpRequestCommand::HttpRequestCommand setWriteCheckSocket(getSocket()); } -HttpRequestCommand::~HttpRequestCommand() {} +HttpRequestCommand::~HttpRequestCommand() +{ + if(backupConnectionInfo_) { + backupConnectionInfo_->cancel = true; + } +} namespace { SharedHandle @@ -122,14 +128,52 @@ createHttpRequest(const SharedHandle& req, } } // namespace +bool HttpRequestCommand::noCheck() { + return backupConnectionInfo_ && !backupConnectionInfo_->ipaddr.empty(); +} + bool HttpRequestCommand::executeInternal() { //socket->setBlockingMode(); if(httpConnection_->sendBufferIsEmpty()) { + if(backupConnectionInfo_ && !backupConnectionInfo_->ipaddr.empty()) { + A2_LOG_INFO(fmt("CUID#%"PRId64" - Use backup connection address %s", + getCuid(), backupConnectionInfo_->ipaddr.c_str())); + getDownloadEngine()->markBadIPAddress + (getRequest()->getConnectedHostname(), + getRequest()->getConnectedAddr(), + getRequest()->getConnectedPort()); + + getRequest()->setConnectedAddrInfo(getRequest()->getConnectedHostname(), + backupConnectionInfo_->ipaddr, + getRequest()->getConnectedPort()); + + SharedHandle socketRecvBuffer + (new SocketRecvBuffer(backupConnectionInfo_->socket)); + SharedHandle httpConnection + (new HttpConnection(getCuid(), backupConnectionInfo_->socket, + socketRecvBuffer)); + HttpRequestCommand* c = + new HttpRequestCommand(getCuid(), getRequest(), getFileEntry(), + getRequestGroup(), + httpConnection, + getDownloadEngine(), + backupConnectionInfo_->socket); + c->setProxyRequest(proxyRequest_); + c->setStatus(STATUS_ONESHOT_REALTIME); + getDownloadEngine()->setNoWait(true); + getDownloadEngine()->addCommand(c); + backupConnectionInfo_.reset(); + return true; + } if(!checkIfConnectionEstablished (getSocket(), getRequest()->getConnectedHostname(), getRequest()->getConnectedAddr(), getRequest()->getConnectedPort())) { return true; } + if(backupConnectionInfo_) { + backupConnectionInfo_->cancel = true; + backupConnectionInfo_.reset(); + } #ifdef ENABLE_SSL if(getRequest()->getProtocol() == "https") { if(!getSocket()->tlsConnect(getRequest()->getHost())) { @@ -235,4 +279,10 @@ void HttpRequestCommand::setProxyRequest proxyRequest_ = proxyRequest; } +void HttpRequestCommand::setBackupConnectInfo +(const SharedHandle& info) +{ + backupConnectionInfo_ = info; +} + } // namespace aria2 diff --git a/src/HttpRequestCommand.h b/src/HttpRequestCommand.h index 8f6d37f9..6ca2278b 100644 --- a/src/HttpRequestCommand.h +++ b/src/HttpRequestCommand.h @@ -41,6 +41,7 @@ namespace aria2 { class HttpConnection; class SocketCore; +class BackupConnectInfo; // HttpRequestCommand sends HTTP request header to remote server. // Because network I/O is non-blocking, execute() returns false if all @@ -53,8 +54,11 @@ private: SharedHandle proxyRequest_; SharedHandle httpConnection_; + + SharedHandle backupConnectionInfo_; protected: virtual bool executeInternal(); + virtual bool noCheck(); public: HttpRequestCommand(cuid_t cuid, const SharedHandle& req, @@ -66,6 +70,7 @@ public: virtual ~HttpRequestCommand(); void setProxyRequest(const SharedHandle& proxyRequest); + void setBackupConnectInfo(const SharedHandle& info); }; } // namespace aria2 diff --git a/src/InitiateConnectionCommand.cc b/src/InitiateConnectionCommand.cc index baee1f74..c4d084fa 100644 --- a/src/InitiateConnectionCommand.cc +++ b/src/InitiateConnectionCommand.cc @@ -51,6 +51,7 @@ #include "RecoverableException.h" #include "fmt.h" #include "SocketRecvBuffer.h" +#include "BackupIPv4ConnectCommand.h" namespace aria2 { @@ -127,4 +128,36 @@ void InitiateConnectionCommand::setConnectedAddrInfo req->setConnectedAddrInfo(hostname, peerAddr.first, peerAddr.second); } +SharedHandle +InitiateConnectionCommand::createBackupIPv4ConnectCommand +(const std::string& hostname, const std::string& ipaddr, uint16_t port, + Command* mainCommand) +{ + // Prepare IPv4 backup connection attemp in "Happy Eyeballs" + // fashion. + SharedHandle info; + char buf[sizeof(in6_addr)]; + if(inetPton(AF_INET6, ipaddr.c_str(), &buf) == -1) { + return info; + } + A2_LOG_INFO("Searching IPv4 address for backup connection attempt"); + std::vector addrs; + getDownloadEngine()->findAllCachedIPAddresses(std::back_inserter(addrs), + hostname, port); + for(std::vector::const_iterator i = addrs.begin(), + eoi = addrs.end(); i != eoi; ++i) { + if(inetPton(AF_INET, (*i).c_str(), &buf) == 0) { + info.reset(new BackupConnectInfo()); + BackupIPv4ConnectCommand* command = new BackupIPv4ConnectCommand + (getDownloadEngine()->newCUID(), *i, port, info, mainCommand, + getRequestGroup(), getDownloadEngine()); + A2_LOG_INFO(fmt("Issue backup connection command CUID#%"PRId64 + ", addr=%s", command->getCuid(), (*i).c_str())); + getDownloadEngine()->addCommand(command); + return info; + } + } + return info; +} + } // namespace aria2 diff --git a/src/InitiateConnectionCommand.h b/src/InitiateConnectionCommand.h index 7b52b353..374de527 100644 --- a/src/InitiateConnectionCommand.h +++ b/src/InitiateConnectionCommand.h @@ -39,6 +39,8 @@ namespace aria2 { +class BackupConnectInfo; + class InitiateConnectionCommand : public AbstractCommand { protected: /** @@ -64,6 +66,10 @@ protected: (const SharedHandle& req, const std::string& hostname, const SharedHandle& socket); + + SharedHandle createBackupIPv4ConnectCommand + (const std::string& hostname, const std::string& ipaddr, uint16_t port, + Command* mainCommand); public: InitiateConnectionCommand(cuid_t cuid, const SharedHandle& req, const SharedHandle& fileEntry, diff --git a/src/Makefile.am b/src/Makefile.am index 2cc7ba21..6eeee32f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -245,7 +245,8 @@ SRCS = SocketCore.cc SocketCore.h\ WrDiskCacheEntry.cc WrDiskCacheEntry.h\ GroupId.cc GroupId.h\ IndexedList.h\ - SaveSessionCommand.h SaveSessionCommand.cc + SaveSessionCommand.h SaveSessionCommand.cc\ + BackupIPv4ConnectCommand.h BackupIPv4ConnectCommand.cc if MINGW_BUILD SRCS += WinConsoleFile.cc WinConsoleFile.h