Implement simple Happy Eyeballs for HTTP/FTP downloads

pull/60/head
Tatsuhiro Tsujikawa 2013-04-01 00:12:27 +09:00
parent d671d8bf36
commit 597e1a5c1b
19 changed files with 502 additions and 6 deletions

View File

@ -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 ||

View File

@ -123,6 +123,11 @@ protected:
return socket_;
}
SharedHandle<SocketCore>& getSocket()
{
return socket_;
}
void setSocket(const SharedHandle<SocketCore>& 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<Request>& req,

View File

@ -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> 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<BackupConnectInfo>& info)
{
backupConnectionInfo_ = info;
}
} // namespace aria2

View File

@ -41,19 +41,28 @@ namespace aria2 {
class HttpConnection;
class SocketCore;
class BackupConnectInfo;
class AbstractProxyRequestCommand : public AbstractCommand {
private:
SharedHandle<Request> proxyRequest_;
SharedHandle<HttpConnection> httpConnection_;
SharedHandle<BackupConnectInfo> backupConnectionInfo_;
protected:
virtual bool executeInternal();
virtual bool noCheck();
const SharedHandle<HttpConnection>& getHttpConnection() const
{
return httpConnection_;
}
const SharedHandle<Request>& getProxyRequest() const
{
return proxyRequest_;
}
public:
AbstractProxyRequestCommand(cuid_t cuid,
const SharedHandle<Request>& req,
@ -66,6 +75,8 @@ public:
virtual ~AbstractProxyRequestCommand();
virtual Command* getNextCommand() = 0;
virtual Command* createSelf(const SharedHandle<SocketCore>& socket) = 0;
void setBackupConnectInfo(const SharedHandle<BackupConnectInfo>& info);
};
} // namespace aria2

View File

@ -0,0 +1,140 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2013 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#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<BackupConnectInfo>& 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

View File

@ -0,0 +1,89 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2013 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#ifndef BACKUP_IPV4_CONNECT_COMMAND_H
#define BACKUP_IPV4_CONNECT_COMMAND_H
#include "Command.h"
#include <string>
#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<SocketCore> 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<BackupConnectInfo>& info,
Command* mainCommand,
RequestGroup* requestGroup, DownloadEngine* e);
~BackupIPv4ConnectCommand();
virtual bool execute();
private:
std::string ipaddr_;
uint16_t port_;
SharedHandle<SocketCore> socket_;
SharedHandle<BackupConnectInfo> info_;
Command* mainCommand_;
RequestGroup* requestGroup_;
DownloadEngine* e_;
Timer startTime_;
Timer timeoutCheck_;
time_t timeout_;
};
} // namespace aria2
#endif // BACKUP_IPV4_CONNECT_COMMAND_H

View File

@ -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> 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> 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> backupConnectInfo
= createBackupIPv4ConnectCommand(hostname, addr, port, c);
if(backupConnectInfo) {
c->setBackupConnectInfo(backupConnectInfo);
}
command = c;
} else {
// options contains "baseWorkingDir"

View File

@ -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<BackupConnectInfo>& info)
{
backupConnectionInfo_ = info;
}
} // namespace aria2

View File

@ -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<std::string> cwdDirs_;
SharedHandle<BackupConnectInfo> backupConnectionInfo_;
protected:
virtual bool executeInternal();
virtual bool noCheck();
public:
FtpNegotiationCommand(cuid_t cuid,
const SharedHandle<Request>& req,
@ -165,6 +169,7 @@ public:
Seq seq = SEQ_RECV_GREETING,
const std::string& baseWorkingDir = "/");
virtual ~FtpNegotiationCommand();
void setBackupConnectInfo(const SharedHandle<BackupConnectInfo>& info);
};
} // namespace aria2

View File

@ -63,4 +63,12 @@ Command* FtpTunnelRequestCommand::getNextCommand()
getHttpConnection(), getDownloadEngine(), getSocket());
}
Command* FtpTunnelRequestCommand::createSelf
(const SharedHandle<SocketCore>& socket)
{
return new FtpTunnelRequestCommand(getCuid(), getRequest(), getFileEntry(),
getRequestGroup(), getDownloadEngine(),
getProxyRequest(), socket);
}
} // namespace aria2

View File

@ -53,6 +53,8 @@ public:
virtual ~FtpTunnelRequestCommand();
virtual Command* getNextCommand();
virtual Command* createSelf(const SharedHandle<SocketCore>& socket);
};
} // namespace aria2

View File

@ -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<BackupConnectInfo> backupConnectionInfo
= createBackupIPv4ConnectCommand(hostname, addr, port, c);
if(backupConnectionInfo) {
c->setBackupConnectInfo(backupConnectionInfo);
}
command = c;
} else if(proxyMethod == V_GET) {
SharedHandle<SocketRecvBuffer> socketRecvBuffer
@ -107,6 +113,11 @@ Command* HttpInitiateConnectionCommand::createNextCommand
getDownloadEngine(),
getSocket());
c->setProxyRequest(proxyRequest);
SharedHandle<BackupConnectInfo> 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<SocketCore> 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> backupConnectInfo
= createBackupIPv4ConnectCommand(hostname, addr, port, c);
if(backupConnectInfo) {
c->setBackupConnectInfo(backupConnectInfo);
}
}
command = c;
}
return command;

View File

@ -62,4 +62,16 @@ Command* HttpProxyRequestCommand::getNextCommand()
getHttpConnection(), getDownloadEngine(), getSocket());
}
Command* HttpProxyRequestCommand::createSelf
(const SharedHandle<SocketCore>& socket)
{
return new HttpProxyRequestCommand(getCuid(),
getRequest(),
getFileEntry(),
getRequestGroup(),
getDownloadEngine(),
getProxyRequest(),
socket);
}
} // namespace aria2

View File

@ -53,6 +53,8 @@ public:
virtual ~HttpProxyRequestCommand();
virtual Command* getNextCommand();
virtual Command* createSelf(const SharedHandle<SocketCore>& socket);
};
} // namespace aria2

View File

@ -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<HttpRequest>
@ -122,14 +128,52 @@ createHttpRequest(const SharedHandle<Request>& 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> socketRecvBuffer
(new SocketRecvBuffer(backupConnectionInfo_->socket));
SharedHandle<HttpConnection> 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<BackupConnectInfo>& info)
{
backupConnectionInfo_ = info;
}
} // namespace aria2

View File

@ -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<Request> proxyRequest_;
SharedHandle<HttpConnection> httpConnection_;
SharedHandle<BackupConnectInfo> backupConnectionInfo_;
protected:
virtual bool executeInternal();
virtual bool noCheck();
public:
HttpRequestCommand(cuid_t cuid,
const SharedHandle<Request>& req,
@ -66,6 +70,7 @@ public:
virtual ~HttpRequestCommand();
void setProxyRequest(const SharedHandle<Request>& proxyRequest);
void setBackupConnectInfo(const SharedHandle<BackupConnectInfo>& info);
};
} // namespace aria2

View File

@ -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<BackupConnectInfo>
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<BackupConnectInfo> 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<std::string> addrs;
getDownloadEngine()->findAllCachedIPAddresses(std::back_inserter(addrs),
hostname, port);
for(std::vector<std::string>::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

View File

@ -39,6 +39,8 @@
namespace aria2 {
class BackupConnectInfo;
class InitiateConnectionCommand : public AbstractCommand {
protected:
/**
@ -64,6 +66,10 @@ protected:
(const SharedHandle<Request>& req,
const std::string& hostname,
const SharedHandle<SocketCore>& socket);
SharedHandle<BackupConnectInfo> createBackupIPv4ConnectCommand
(const std::string& hostname, const std::string& ipaddr, uint16_t port,
Command* mainCommand);
public:
InitiateConnectionCommand(cuid_t cuid, const SharedHandle<Request>& req,
const SharedHandle<FileEntry>& fileEntry,

View File

@ -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