mirror of https://github.com/aria2/aria2
Implement simple Happy Eyeballs for HTTP/FTP downloads
parent
d671d8bf36
commit
597e1a5c1b
|
@ -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 ||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -53,6 +53,8 @@ public:
|
|||
virtual ~FtpTunnelRequestCommand();
|
||||
|
||||
virtual Command* getNextCommand();
|
||||
|
||||
virtual Command* createSelf(const SharedHandle<SocketCore>& socket);
|
||||
};
|
||||
|
||||
} // namespace aria2
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -53,6 +53,8 @@ public:
|
|||
virtual ~HttpProxyRequestCommand();
|
||||
|
||||
virtual Command* getNextCommand();
|
||||
|
||||
virtual Command* createSelf(const SharedHandle<SocketCore>& socket);
|
||||
};
|
||||
|
||||
} // namespace aria2
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue