2009-07-03 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

Try all available addresses returned by DNS until it gets
	connected in HTTP(S)/FTP download
	* src/AbstractCommand.cc
	* src/AbstractCommand.h
	* src/AbstractProxyRequestCommand.cc
	* src/AbstractProxyRequestCommand.h
	* src/DNSCache.h
	* src/DownloadEngine.cc
	* src/DownloadEngine.h
	* src/FtpInitiateConnectionCommand.cc
	* src/FtpInitiateConnectionCommand.h
	* src/FtpNegotiationCommand.cc
	* src/FtpNegotiationCommand.h
	* src/HttpInitiateConnectionCommand.cc
	* src/HttpInitiateConnectionCommand.h
	* src/HttpRequestCommand.cc
	* src/HttpRequestCommand.h
	* src/InitiateConnectionCommand.cc
	* src/InitiateConnectionCommand.h
	* test/DNSCacheTest.cc
	* test/Makefile.am
	* test/SimpleDNSCacheTest.cc
pull/1/head
Tatsuhiro Tsujikawa 2009-07-02 15:18:13 +00:00
parent 8796993c71
commit 01fdb2aaeb
22 changed files with 351 additions and 130 deletions

View File

@ -1,3 +1,28 @@
2009-07-03 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Try all available addresses returned by DNS until it gets
connected in HTTP(S)/FTP download
* src/AbstractCommand.cc
* src/AbstractCommand.h
* src/AbstractProxyRequestCommand.cc
* src/AbstractProxyRequestCommand.h
* src/DNSCache.h
* src/DownloadEngine.cc
* src/DownloadEngine.h
* src/FtpInitiateConnectionCommand.cc
* src/FtpInitiateConnectionCommand.h
* src/FtpNegotiationCommand.cc
* src/FtpNegotiationCommand.h
* src/HttpInitiateConnectionCommand.cc
* src/HttpInitiateConnectionCommand.h
* src/HttpRequestCommand.cc
* src/HttpRequestCommand.h
* src/InitiateConnectionCommand.cc
* src/InitiateConnectionCommand.h
* test/DNSCacheTest.cc
* test/Makefile.am
* test/SimpleDNSCacheTest.cc
2009-07-01 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net> 2009-07-01 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Updated doc Updated doc

View File

@ -539,12 +539,28 @@ void AbstractCommand::prepareForNextAction(Command* nextCommand)
e->setNoWait(true); e->setNoWait(true);
} }
void AbstractCommand::checkIfConnectionEstablished bool AbstractCommand::checkIfConnectionEstablished
(const SharedHandle<SocketCore>& socket) (const SharedHandle<SocketCore>& socket,
const std::string& connectedHostname,
const std::string& connectedAddr,
uint16_t connectedPort)
{ {
if(socket->isReadable(0)) { if(socket->isReadable(0)) {
std::string error = socket->getSocketError(); std::string error = socket->getSocketError();
if(!error.empty()) { if(!error.empty()) {
e->markBadIPAddress(connectedHostname, connectedAddr, connectedPort);
if(!e->findCachedIPAddress(connectedHostname, connectedPort).empty()) {
logger->info("CUID#%d - Could not to connect to %s:%u."
" Trying another address",
cuid, connectedAddr.c_str(), connectedPort);
Command* command =
InitiateConnectionCommandFactory::createInitiateConnectionCommand
(cuid, req, _fileEntry, _requestGroup, e);
e->setNoWait(true);
e->commands.push_back(command);
return false;
}
e->removeCachedIPAddress(connectedHostname, connectedPort);
// Don't set error if proxy server is used and its method is GET. // Don't set error if proxy server is used and its method is GET.
if(resolveProxyMethod(req->getProtocol()) != V_GET || if(resolveProxyMethod(req->getProtocol()) != V_GET ||
!isProxyRequest(req->getProtocol(), getOption())) { !isProxyRequest(req->getProtocol(), getOption())) {
@ -555,6 +571,7 @@ void AbstractCommand::checkIfConnectionEstablished
(StringFormat(MSG_ESTABLISHING_CONNECTION_FAILED, error.c_str()).str()); (StringFormat(MSG_ESTABLISHING_CONNECTION_FAILED, error.c_str()).str());
} }
} }
return true;
} }
const std::string& AbstractCommand::resolveProxyMethod const std::string& AbstractCommand::resolveProxyMethod

View File

@ -102,7 +102,16 @@ protected:
void prepareForNextAction(Command* nextCommand = 0); void prepareForNextAction(Command* nextCommand = 0);
void checkIfConnectionEstablished(const SharedHandle<SocketCore>& socket); // Check if socket is connected. If socket is not connected and
// there are other addresses to try, command is created using
// InitiateConnectionCommandFactory and it is pushed to
// DownloadEngine and returns false. If no addresses left, DlRetryEx
// exception is thrown.
bool checkIfConnectionEstablished
(const SharedHandle<SocketCore>& socket,
const std::string& connectedHostname,
const std::string& connectedAddr,
uint16_t connectedPort);
/* /*
* Returns true if proxy for the procol indicated by Request::getProtocol() * Returns true if proxy for the procol indicated by Request::getProtocol()

View File

@ -72,6 +72,10 @@ AbstractProxyRequestCommand::~AbstractProxyRequestCommand() {}
bool AbstractProxyRequestCommand::executeInternal() { bool AbstractProxyRequestCommand::executeInternal() {
//socket->setBlockingMode(); //socket->setBlockingMode();
if(httpConnection->sendBufferIsEmpty()) { if(httpConnection->sendBufferIsEmpty()) {
if(!checkIfConnectionEstablished
(socket, _connectedHostname, _connectedAddr, _connectedPort)) {
return true;
}
HttpRequestHandle httpRequest(new HttpRequest()); HttpRequestHandle httpRequest(new HttpRequest());
httpRequest->setUserAgent(getOption()->get(PREF_USER_AGENT)); httpRequest->setUserAgent(getOption()->get(PREF_USER_AGENT));
httpRequest->setRequest(req); httpRequest->setRequest(req);

View File

@ -48,6 +48,10 @@ protected:
SharedHandle<HttpConnection> httpConnection; SharedHandle<HttpConnection> httpConnection;
std::string _connectedHostname;
std::string _connectedAddr;
uint16_t _connectedPort;
virtual bool executeInternal(); virtual bool executeInternal();
public: public:
AbstractProxyRequestCommand(int cuid, AbstractProxyRequestCommand(int cuid,
@ -61,6 +65,14 @@ public:
virtual ~AbstractProxyRequestCommand(); virtual ~AbstractProxyRequestCommand();
virtual Command* getNextCommand() = 0; virtual Command* getNextCommand() = 0;
void setConnectedAddr
(const std::string& hostname, const std::string& addr, uint16_t port)
{
_connectedHostname = hostname;
_connectedAddr = addr;
_connectedPort = port;
}
}; };
} // namespace aria2 } // namespace aria2

View File

@ -38,57 +38,102 @@
#include "common.h" #include "common.h"
#include <string> #include <string>
#include <map> #include <deque>
#include <algorithm>
#include "A2STR.h" #include "A2STR.h"
namespace aria2 { namespace aria2 {
class DNSCache { class DNSCache {
public:
virtual ~DNSCache() {}
virtual const std::string& find(const std::string& hostname) const = 0;
virtual void put(const std::string& hostname, const std::string& ipaddr) = 0;
};
class SimpleDNSCache : public DNSCache {
private: private:
std::map<std::string, std::string> _table; struct CacheEntry {
public: std::string _hostname;
SimpleDNSCache() {} std::string _addr;
uint16_t _port;
bool _good;
CacheEntry
(const std::string& hostname, const std::string& addr, uint16_t port):
_hostname(hostname), _addr(addr), _port(port), _good(true) {}
virtual ~SimpleDNSCache() {} void markBad() { _good = false; }
virtual const std::string& find(const std::string& hostname) const bool operator<(const CacheEntry& e) const
{
int r = _hostname.compare(e._hostname);
if(r != 0) {
return r < 0;
}
if(_port != e._port) {
return _port < e._port;
}
return _addr < e._addr;
}
bool operator==(const CacheEntry& e) const
{
return _hostname == e._hostname && _addr == e._addr && _port == e._port;
}
};
std::deque<CacheEntry> _entries;
std::deque<CacheEntry>::iterator findEntry
(const std::string& hostname, const std::string& ipaddr, uint16_t port)
{ {
std::map<std::string, std::string>::const_iterator i = CacheEntry target(hostname, ipaddr, port);
_table.find(hostname); std::deque<CacheEntry>::iterator i =
if(i == _table.end()) { std::lower_bound(_entries.begin(), _entries.end(), target);
return A2STR::NIL; if(i != _entries.end() && (*i) == target) {
return i;
} else { } else {
return (*i).second; return _entries.end();
} }
} }
virtual void put(const std::string& hostname, const std::string& ipaddr)
{
_table[hostname] = ipaddr;
}
};
class NullDNSCache : public DNSCache {
public: public:
virtual ~NullDNSCache() {} const std::string& find(const std::string& hostname, uint16_t port) const
virtual const std::string& find(const std::string& hostname)
{ {
CacheEntry target(hostname, A2STR::NIL, port);
std::deque<CacheEntry>::const_iterator i =
std::lower_bound(_entries.begin(), _entries.end(), target);
for(; i != _entries.end() && (*i)._hostname == hostname && (*i)._port == port; ++i) {
if((*i)._good) {
return (*i)._addr;
}
}
return A2STR::NIL; return A2STR::NIL;
} }
virtual void put(const std::string& hostname, const std::string& ipaddr) {} void put
(const std::string& hostname, const std::string& ipaddr, uint16_t port)
{
CacheEntry target(hostname, ipaddr, port);
std::deque<CacheEntry>::iterator i =
std::lower_bound(_entries.begin(), _entries.end(), target);
if(i == _entries.end() || !((*i) == target)) {
_entries.insert(i, target);
}
}
void markBad
(const std::string& hostname, const std::string& ipaddr, uint16_t port)
{
std::deque<CacheEntry>::iterator i = findEntry(hostname, ipaddr, port);
if(i != _entries.end()) {
(*i).markBad();
}
}
void remove(const std::string& hostname, uint16_t port)
{
CacheEntry target(hostname, A2STR::NIL, port);
std::deque<CacheEntry>::iterator i =
std::lower_bound(_entries.begin(), _entries.end(), target);
for(; i != _entries.end() && (*i)._hostname == hostname && (*i)._port == port;) {
i = _entries.erase(i);
}
}
}; };
} // namespace aria2 } // namespace aria2

View File

@ -92,7 +92,7 @@ DownloadEngine::DownloadEngine(const SharedHandle<EventPoll>& eventPoll):
_refreshInterval(DEFAULT_REFRESH_INTERVAL), _refreshInterval(DEFAULT_REFRESH_INTERVAL),
_cookieStorage(new CookieStorage()), _cookieStorage(new CookieStorage()),
_btRegistry(new BtRegistry()), _btRegistry(new BtRegistry()),
_dnsCache(new SimpleDNSCache()) _dnsCache(new DNSCache())
{} {}
DownloadEngine::~DownloadEngine() { DownloadEngine::~DownloadEngine() {
@ -446,15 +446,27 @@ cuid_t DownloadEngine::newCUID()
} }
const std::string& DownloadEngine::findCachedIPAddress const std::string& DownloadEngine::findCachedIPAddress
(const std::string& hostname) const (const std::string& hostname, uint16_t port) const
{ {
return _dnsCache->find(hostname); return _dnsCache->find(hostname, port);
} }
void DownloadEngine::cacheIPAddress void DownloadEngine::cacheIPAddress
(const std::string& hostname, const std::string& ipaddr) (const std::string& hostname, const std::string& ipaddr, uint16_t port)
{ {
_dnsCache->put(hostname, ipaddr); _dnsCache->put(hostname, ipaddr, port);
}
void DownloadEngine::markBadIPAddress
(const std::string& hostname, const std::string& ipaddr, uint16_t port)
{
_dnsCache->markBad(hostname, ipaddr, port);
}
void DownloadEngine::removeCachedIPAddress
(const std::string& hostname, uint16_t port)
{
_dnsCache->remove(hostname, port);
} }
void DownloadEngine::setAuthConfigFactory void DownloadEngine::setAuthConfigFactory

View File

@ -244,9 +244,16 @@ public:
cuid_t newCUID(); cuid_t newCUID();
const std::string& findCachedIPAddress(const std::string& hostname) const; const std::string& findCachedIPAddress
(const std::string& hostname, uint16_t port) const;
void cacheIPAddress(const std::string& hostname, const std::string& ipaddr); void cacheIPAddress
(const std::string& hostname, const std::string& ipaddr, uint16_t port);
void markBadIPAddress
(const std::string& hostname, const std::string& ipaddr, uint16_t port);
void removeCachedIPAddress(const std::string& hostname, uint16_t port);
void setAuthConfigFactory(const SharedHandle<AuthConfigFactory>& factory); void setAuthConfigFactory(const SharedHandle<AuthConfigFactory>& factory);

View File

@ -65,7 +65,8 @@ FtpInitiateConnectionCommand::FtpInitiateConnectionCommand
FtpInitiateConnectionCommand::~FtpInitiateConnectionCommand() {} FtpInitiateConnectionCommand::~FtpInitiateConnectionCommand() {}
Command* FtpInitiateConnectionCommand::createNextCommand Command* FtpInitiateConnectionCommand::createNextCommand
(const std::deque<std::string>& resolvedAddresses, (const std::string& hostname, const std::string& addr, uint16_t port,
const std::deque<std::string>& resolvedAddresses,
const SharedHandle<Request>& proxyRequest) const SharedHandle<Request>& proxyRequest)
{ {
Command* command; Command* command;
@ -75,11 +76,9 @@ Command* FtpInitiateConnectionCommand::createNextCommand
e->popPooledSocket(options, req->getHost(), req->getPort()); e->popPooledSocket(options, req->getHost(), req->getPort());
std::string proxyMethod = resolveProxyMethod(req->getProtocol()); std::string proxyMethod = resolveProxyMethod(req->getProtocol());
if(pooledSocket.isNull()) { if(pooledSocket.isNull()) {
logger->info(MSG_CONNECTING_TO_SERVER, cuid, logger->info(MSG_CONNECTING_TO_SERVER, cuid, addr.c_str(), port);
proxyRequest->getHost().c_str(), proxyRequest->getPort());
socket.reset(new SocketCore()); socket.reset(new SocketCore());
socket->establishConnection(resolvedAddresses.front(), socket->establishConnection(addr, port);
proxyRequest->getPort());
if(proxyMethod == V_GET) { if(proxyMethod == V_GET) {
// Use GET for FTP via HTTP proxy. // Use GET for FTP via HTTP proxy.
@ -90,12 +89,16 @@ Command* FtpInitiateConnectionCommand::createNextCommand
HttpRequestCommand* c = HttpRequestCommand* c =
new HttpRequestCommand(cuid, req, _fileEntry, new HttpRequestCommand(cuid, req, _fileEntry,
_requestGroup, hc, e, socket); _requestGroup, hc, e, socket);
c->setConnectedAddr(hostname, addr, port);
c->setProxyRequest(proxyRequest); c->setProxyRequest(proxyRequest);
command = c; command = c;
} else if(proxyMethod == V_TUNNEL) { } else if(proxyMethod == V_TUNNEL) {
command = new FtpTunnelRequestCommand(cuid, req, _fileEntry, FtpTunnelRequestCommand* c =
_requestGroup, e, new FtpTunnelRequestCommand(cuid, req, _fileEntry,
proxyRequest, socket); _requestGroup, e,
proxyRequest, socket);
c->setConnectedAddr(hostname, addr, port);
command = c;
} else { } else {
// TODO // TODO
throw DL_ABORT_EX("ERROR"); throw DL_ABORT_EX("ERROR");
@ -128,12 +131,14 @@ Command* FtpInitiateConnectionCommand::createNextCommand
SharedHandle<SocketCore> pooledSocket = SharedHandle<SocketCore> pooledSocket =
e->popPooledSocket(options, resolvedAddresses, req->getPort()); e->popPooledSocket(options, resolvedAddresses, req->getPort());
if(pooledSocket.isNull()) { if(pooledSocket.isNull()) {
logger->info(MSG_CONNECTING_TO_SERVER, cuid, req->getHost().c_str(), logger->info(MSG_CONNECTING_TO_SERVER, cuid, addr.c_str(), port);
req->getPort());
socket.reset(new SocketCore()); socket.reset(new SocketCore());
socket->establishConnection(resolvedAddresses.front(), req->getPort()); socket->establishConnection(addr, port);
command = new FtpNegotiationCommand(cuid, req, _fileEntry, FtpNegotiationCommand* c =
_requestGroup, e, socket); new FtpNegotiationCommand(cuid, req, _fileEntry,
_requestGroup, e, socket);
c->setConnectedAddr(hostname, addr, port);
command = c;
} else { } else {
command = command =
new FtpNegotiationCommand(cuid, req, _fileEntry, new FtpNegotiationCommand(cuid, req, _fileEntry,

View File

@ -42,7 +42,8 @@ namespace aria2 {
class FtpInitiateConnectionCommand : public InitiateConnectionCommand { class FtpInitiateConnectionCommand : public InitiateConnectionCommand {
protected: protected:
virtual Command* createNextCommand virtual Command* createNextCommand
(const std::deque<std::string>& resolvedAddresses, (const std::string& hostname, const std::string& addr, uint16_t port,
const std::deque<std::string>& resolvedAddresses,
const SharedHandle<Request>& proxyRequest); const SharedHandle<Request>& proxyRequest);
public: public:
FtpInitiateConnectionCommand(int cuid, const SharedHandle<Request>& req, FtpInitiateConnectionCommand(int cuid, const SharedHandle<Request>& req,

View File

@ -118,6 +118,8 @@ bool FtpNegotiationCommand::executeInternal() {
sequence = SEQ_PREPARE_SERVER_SOCKET; sequence = SEQ_PREPARE_SERVER_SOCKET;
} }
return false; return false;
} else if(sequence == SEQ_EXIT) {
return true;
} else { } else {
e->commands.push_back(this); e->commands.push_back(this);
return false; return false;
@ -125,7 +127,11 @@ bool FtpNegotiationCommand::executeInternal() {
} }
bool FtpNegotiationCommand::recvGreeting() { bool FtpNegotiationCommand::recvGreeting() {
checkIfConnectionEstablished(socket); if(!checkIfConnectionEstablished
(socket, _connectedHostname, _connectedAddr, _connectedPort)) {
sequence = SEQ_EXIT;
return false;
}
setTimeout(_requestGroup->getTimeout()); setTimeout(_requestGroup->getTimeout());
//socket->setBlockingMode(); //socket->setBlockingMode();
disableWriteCheckSocket(); disableWriteCheckSocket();

View File

@ -76,6 +76,7 @@ public:
SEQ_HEAD_OK, SEQ_HEAD_OK,
SEQ_DOWNLOAD_ALREADY_COMPLETED, SEQ_DOWNLOAD_ALREADY_COMPLETED,
SEQ_FILE_PREPARATION, // File allocation after SIZE command SEQ_FILE_PREPARATION, // File allocation after SIZE command
SEQ_EXIT
}; };
private: private:
bool recvGreeting(); bool recvGreeting();
@ -118,6 +119,10 @@ private:
SharedHandle<SocketCore> serverSocket; SharedHandle<SocketCore> serverSocket;
Seq sequence; Seq sequence;
SharedHandle<FtpConnection> ftp; SharedHandle<FtpConnection> ftp;
std::string _connectedHostname;
std::string _connectedAddr;
uint16_t _connectedPort;
protected: protected:
virtual bool executeInternal(); virtual bool executeInternal();
public: public:
@ -130,6 +135,14 @@ public:
Seq seq = SEQ_RECV_GREETING, Seq seq = SEQ_RECV_GREETING,
const std::string& baseWorkingDir = "/"); const std::string& baseWorkingDir = "/");
virtual ~FtpNegotiationCommand(); virtual ~FtpNegotiationCommand();
void setConnectedAddr
(const std::string& hostname, const std::string& addr, uint16_t port)
{
_connectedHostname = hostname;
_connectedAddr = addr;
_connectedPort = port;
}
}; };
} // namespace aria2 } // namespace aria2

View File

@ -62,7 +62,8 @@ HttpInitiateConnectionCommand::HttpInitiateConnectionCommand
HttpInitiateConnectionCommand::~HttpInitiateConnectionCommand() {} HttpInitiateConnectionCommand::~HttpInitiateConnectionCommand() {}
Command* HttpInitiateConnectionCommand::createNextCommand Command* HttpInitiateConnectionCommand::createNextCommand
(const std::deque<std::string>& resolvedAddresses, (const std::string& hostname, const std::string& addr, uint16_t port,
const std::deque<std::string>& resolvedAddresses,
const SharedHandle<Request>& proxyRequest) const SharedHandle<Request>& proxyRequest)
{ {
Command* command; Command* command;
@ -71,16 +72,17 @@ Command* HttpInitiateConnectionCommand::createNextCommand
e->popPooledSocket(req->getHost(), req->getPort()); e->popPooledSocket(req->getHost(), req->getPort());
std::string proxyMethod = resolveProxyMethod(req->getProtocol()); std::string proxyMethod = resolveProxyMethod(req->getProtocol());
if(pooledSocket.isNull()) { if(pooledSocket.isNull()) {
logger->info(MSG_CONNECTING_TO_SERVER, cuid, logger->info(MSG_CONNECTING_TO_SERVER, cuid, addr.c_str(), port);
proxyRequest->getHost().c_str(), proxyRequest->getPort());
socket.reset(new SocketCore()); socket.reset(new SocketCore());
socket->establishConnection(resolvedAddresses.front(), socket->establishConnection(addr, port);
proxyRequest->getPort());
if(proxyMethod == V_TUNNEL) { if(proxyMethod == V_TUNNEL) {
command = new HttpProxyRequestCommand(cuid, req, _fileEntry, HttpProxyRequestCommand* c =
_requestGroup, e, new HttpProxyRequestCommand(cuid, req, _fileEntry,
proxyRequest, socket); _requestGroup, e,
proxyRequest, socket);
c->setConnectedAddr(hostname, addr, port);
command = c;
} else if(proxyMethod == V_GET) { } else if(proxyMethod == V_GET) {
SharedHandle<HttpConnection> httpConnection SharedHandle<HttpConnection> httpConnection
(new HttpConnection(cuid, socket, getOption().get())); (new HttpConnection(cuid, socket, getOption().get()));
@ -89,6 +91,7 @@ Command* HttpInitiateConnectionCommand::createNextCommand
_requestGroup, _requestGroup,
httpConnection, e, httpConnection, e,
socket); socket);
c->setConnectedAddr(hostname, addr, port);
c->setProxyRequest(proxyRequest); c->setProxyRequest(proxyRequest);
command = c; command = c;
} else { } else {
@ -112,16 +115,20 @@ Command* HttpInitiateConnectionCommand::createNextCommand
SharedHandle<SocketCore> pooledSocket = SharedHandle<SocketCore> pooledSocket =
e->popPooledSocket(resolvedAddresses, req->getPort()); e->popPooledSocket(resolvedAddresses, req->getPort());
if(pooledSocket.isNull()) { if(pooledSocket.isNull()) {
logger->info(MSG_CONNECTING_TO_SERVER, cuid, req->getHost().c_str(), logger->info(MSG_CONNECTING_TO_SERVER, cuid, addr.c_str(), port);
req->getPort());
socket.reset(new SocketCore()); socket.reset(new SocketCore());
socket->establishConnection(resolvedAddresses.front(), req->getPort()); socket->establishConnection(addr, port);
} else { } else {
socket = pooledSocket; socket = pooledSocket;
} }
SharedHandle<HttpConnection> httpConnection(new HttpConnection(cuid, socket, getOption().get())); SharedHandle<HttpConnection> httpConnection(new HttpConnection(cuid, socket, getOption().get()));
command = new HttpRequestCommand(cuid, req, _fileEntry, _requestGroup, HttpRequestCommand* c =
httpConnection, e, socket); new HttpRequestCommand(cuid, req, _fileEntry, _requestGroup,
httpConnection, e, socket);
if(pooledSocket.isNull()) {
c->setConnectedAddr(hostname, addr, port);
}
command = c;
} }
return command; return command;
} }

View File

@ -42,7 +42,8 @@ namespace aria2 {
class HttpInitiateConnectionCommand : public InitiateConnectionCommand { class HttpInitiateConnectionCommand : public InitiateConnectionCommand {
protected: protected:
virtual Command* createNextCommand virtual Command* createNextCommand
(const std::deque<std::string>& resolvedAddresses, (const std::string& hostname, const std::string& addr, uint16_t port,
const std::deque<std::string>& resolvedAddresses,
const SharedHandle<Request>& proxyRequest); const SharedHandle<Request>& proxyRequest);
public: public:
HttpInitiateConnectionCommand(int cuid, const SharedHandle<Request>& req, HttpInitiateConnectionCommand(int cuid, const SharedHandle<Request>& req,

View File

@ -112,7 +112,10 @@ bool HttpRequestCommand::executeInternal() {
} }
} }
if(_httpConnection->sendBufferIsEmpty()) { if(_httpConnection->sendBufferIsEmpty()) {
checkIfConnectionEstablished(socket); if(!checkIfConnectionEstablished
(socket, _connectedHostname, _connectedAddr, _connectedPort)) {
return true;
}
if(_segments.empty()) { if(_segments.empty()) {
HttpRequestHandle httpRequest HttpRequestHandle httpRequest

View File

@ -47,6 +47,10 @@ private:
SharedHandle<Request> _proxyRequest; SharedHandle<Request> _proxyRequest;
SharedHandle<HttpConnection> _httpConnection; SharedHandle<HttpConnection> _httpConnection;
std::string _connectedHostname;
std::string _connectedAddr;
uint16_t _connectedPort;
protected: protected:
virtual bool executeInternal(); virtual bool executeInternal();
public: public:
@ -60,6 +64,14 @@ public:
virtual ~HttpRequestCommand(); virtual ~HttpRequestCommand();
void setProxyRequest(const SharedHandle<Request>& proxyRequest); void setProxyRequest(const SharedHandle<Request>& proxyRequest);
void setConnectedAddr
(const std::string& hostname, const std::string& addr, uint16_t port)
{
_connectedHostname = hostname;
_connectedAddr = addr;
_connectedPort = port;
}
}; };
} // namespace aria2 } // namespace aria2

View File

@ -46,6 +46,7 @@
#include "RequestGroup.h" #include "RequestGroup.h"
#include "DownloadContext.h" #include "DownloadContext.h"
#include "Segment.h" #include "Segment.h"
#include "a2functional.h"
namespace aria2 { namespace aria2 {
@ -68,14 +69,17 @@ InitiateConnectionCommand::~InitiateConnectionCommand() {}
bool InitiateConnectionCommand::executeInternal() { bool InitiateConnectionCommand::executeInternal() {
std::string hostname; std::string hostname;
uint16_t port;
SharedHandle<Request> proxyRequest = createProxyRequest(); SharedHandle<Request> proxyRequest = createProxyRequest();
if(proxyRequest.isNull()) { if(proxyRequest.isNull()) {
hostname = req->getHost(); hostname = req->getHost();
port = req->getPort();
} else { } else {
hostname = proxyRequest->getHost(); hostname = proxyRequest->getHost();
port = proxyRequest->getPort();
} }
std::deque<std::string> addrs; std::deque<std::string> addrs;
std::string ipaddr = e->findCachedIPAddress(hostname); std::string ipaddr = e->findCachedIPAddress(hostname, port);
if(ipaddr.empty()) { if(ipaddr.empty()) {
#ifdef ENABLE_ASYNC_DNS #ifdef ENABLE_ASYNC_DNS
if(getOption()->getAsBool(PREF_ASYNC_DNS)) { if(getOption()->getAsBool(PREF_ASYNC_DNS)) {
@ -97,14 +101,18 @@ bool InitiateConnectionCommand::executeInternal() {
} }
logger->info(MSG_NAME_RESOLUTION_COMPLETE, cuid, logger->info(MSG_NAME_RESOLUTION_COMPLETE, cuid,
hostname.c_str(), hostname.c_str(),
addrs.front().c_str()); strjoin(addrs.begin(), addrs.end(), ",").c_str());
e->cacheIPAddress(hostname, addrs.front()); for(std::deque<std::string>::const_iterator i = addrs.begin();
i != addrs.end(); ++i) {
e->cacheIPAddress(hostname, *i, port);
}
ipaddr = e->findCachedIPAddress(hostname, port);
} else { } else {
logger->info(MSG_DNS_CACHE_HIT, cuid, hostname.c_str(), ipaddr.c_str()); logger->info(MSG_DNS_CACHE_HIT, cuid, hostname.c_str(), ipaddr.c_str());
addrs.push_back(ipaddr); addrs.push_back(ipaddr);
} }
Command* command = createNextCommand(hostname, ipaddr, port,
Command* command = createNextCommand(addrs, proxyRequest); addrs, proxyRequest);
e->commands.push_back(command); e->commands.push_back(command);
return true; return true;
} }

View File

@ -49,8 +49,15 @@ protected:
*/ */
virtual bool executeInternal(); virtual bool executeInternal();
// hostname and port are the hostname and port number we are going
// to connect. If proxy server is used, these values are hostname
// and port of proxy server. addr is one of resolved address and we
// use this address this time. resolvedAddresses are all addresses
// resolved. proxyRequest is set if we are going to use proxy
// server.
virtual Command* createNextCommand virtual Command* createNextCommand
(const std::deque<std::string>& resolvedAddresses, (const std::string& hostname, const std::string& addr, uint16_t port,
const std::deque<std::string>& resolvedAddresses,
const SharedHandle<Request>& proxyRequest) = 0; const SharedHandle<Request>& proxyRequest) = 0;
public: public:
InitiateConnectionCommand(int cuid, const SharedHandle<Request>& req, InitiateConnectionCommand(int cuid, const SharedHandle<Request>& req,

64
test/DNSCacheTest.cc Normal file
View File

@ -0,0 +1,64 @@
#include "DNSCache.h"
#include <cppunit/extensions/HelperMacros.h>
namespace aria2 {
class DNSCacheTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(DNSCacheTest);
CPPUNIT_TEST(testFind);
CPPUNIT_TEST(testMarkBad);
CPPUNIT_TEST(testPutBadAddr);
CPPUNIT_TEST(testRemove);
CPPUNIT_TEST_SUITE_END();
DNSCache _cache;
public:
void setUp()
{
_cache = DNSCache();
_cache.put("www", "192.168.0.1", 80);
_cache.put("www", "::1", 80);
_cache.put("ftp", "192.168.0.1", 21);
_cache.put("proxy", "192.168.1.2", 8080);
}
void testFind();
void testMarkBad();
void testPutBadAddr();
void testRemove();
};
CPPUNIT_TEST_SUITE_REGISTRATION(DNSCacheTest);
void DNSCacheTest::testFind()
{
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), _cache.find("www", 80));
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), _cache.find("ftp", 21));
CPPUNIT_ASSERT_EQUAL(std::string("192.168.1.2"), _cache.find("proxy", 8080));
CPPUNIT_ASSERT_EQUAL(std::string(""), _cache.find("www", 8080));
CPPUNIT_ASSERT_EQUAL(std::string(""), _cache.find("another", 80));
}
void DNSCacheTest::testMarkBad()
{
_cache.markBad("www", "192.168.0.1", 80);
CPPUNIT_ASSERT_EQUAL(std::string("::1"), _cache.find("www", 80));
}
void DNSCacheTest::testPutBadAddr()
{
_cache.markBad("www", "192.168.0.1", 80);
_cache.put("www", "192.168.0.1", 80);
CPPUNIT_ASSERT_EQUAL(std::string("::1"), _cache.find("www", 80));
}
void DNSCacheTest::testRemove()
{
_cache.remove("www", 80);
CPPUNIT_ASSERT_EQUAL(std::string(""), _cache.find("www", 80));
}
} // namespace aria2

View File

@ -60,7 +60,7 @@ aria2c_SOURCES = AllTest.cc\
TimeTest.cc\ TimeTest.cc\
FtpConnectionTest.cc\ FtpConnectionTest.cc\
OptionParserTest.cc\ OptionParserTest.cc\
SimpleDNSCacheTest.cc\ DNSCacheTest.cc\
DownloadHelperTest.cc\ DownloadHelperTest.cc\
SequentialPickerTest.cc\ SequentialPickerTest.cc\
RarestPieceSelectorTest.cc\ RarestPieceSelectorTest.cc\

View File

@ -194,12 +194,11 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \
ServerStatTest.cc NsCookieParserTest.cc \ ServerStatTest.cc NsCookieParserTest.cc \
DirectDiskAdaptorTest.cc CookieTest.cc CookieStorageTest.cc \ DirectDiskAdaptorTest.cc CookieTest.cc CookieStorageTest.cc \
TimeTest.cc FtpConnectionTest.cc OptionParserTest.cc \ TimeTest.cc FtpConnectionTest.cc OptionParserTest.cc \
SimpleDNSCacheTest.cc DownloadHelperTest.cc \ DNSCacheTest.cc DownloadHelperTest.cc SequentialPickerTest.cc \
SequentialPickerTest.cc RarestPieceSelectorTest.cc \ RarestPieceSelectorTest.cc PieceStatManTest.cc \
PieceStatManTest.cc InOrderPieceSelector.h \ InOrderPieceSelector.h LongestSequencePieceSelectorTest.cc \
LongestSequencePieceSelectorTest.cc a2algoTest.cc \ a2algoTest.cc bitfieldTest.cc BDETest.cc \
bitfieldTest.cc BDETest.cc DownloadContextTest.cc \ DownloadContextTest.cc XmlRpcRequestParserControllerTest.cc \
XmlRpcRequestParserControllerTest.cc \
XmlRpcRequestProcessorTest.cc XmlRpcMethodTest.cc \ XmlRpcRequestProcessorTest.cc XmlRpcMethodTest.cc \
FallocFileAllocationIteratorTest.cc GZipDecoderTest.cc \ FallocFileAllocationIteratorTest.cc GZipDecoderTest.cc \
Sqlite3MozCookieParserTest.cc MessageDigestHelperTest.cc \ Sqlite3MozCookieParserTest.cc MessageDigestHelperTest.cc \
@ -369,7 +368,7 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) TestUtil.$(OBJEXT) \
NsCookieParserTest.$(OBJEXT) DirectDiskAdaptorTest.$(OBJEXT) \ NsCookieParserTest.$(OBJEXT) DirectDiskAdaptorTest.$(OBJEXT) \
CookieTest.$(OBJEXT) CookieStorageTest.$(OBJEXT) \ CookieTest.$(OBJEXT) CookieStorageTest.$(OBJEXT) \
TimeTest.$(OBJEXT) FtpConnectionTest.$(OBJEXT) \ TimeTest.$(OBJEXT) FtpConnectionTest.$(OBJEXT) \
OptionParserTest.$(OBJEXT) SimpleDNSCacheTest.$(OBJEXT) \ OptionParserTest.$(OBJEXT) DNSCacheTest.$(OBJEXT) \
DownloadHelperTest.$(OBJEXT) SequentialPickerTest.$(OBJEXT) \ DownloadHelperTest.$(OBJEXT) SequentialPickerTest.$(OBJEXT) \
RarestPieceSelectorTest.$(OBJEXT) PieceStatManTest.$(OBJEXT) \ RarestPieceSelectorTest.$(OBJEXT) PieceStatManTest.$(OBJEXT) \
LongestSequencePieceSelectorTest.$(OBJEXT) \ LongestSequencePieceSelectorTest.$(OBJEXT) \
@ -599,14 +598,13 @@ aria2c_SOURCES = AllTest.cc TestUtil.cc TestUtil.h SocketCoreTest.cc \
ServerStatTest.cc NsCookieParserTest.cc \ ServerStatTest.cc NsCookieParserTest.cc \
DirectDiskAdaptorTest.cc CookieTest.cc CookieStorageTest.cc \ DirectDiskAdaptorTest.cc CookieTest.cc CookieStorageTest.cc \
TimeTest.cc FtpConnectionTest.cc OptionParserTest.cc \ TimeTest.cc FtpConnectionTest.cc OptionParserTest.cc \
SimpleDNSCacheTest.cc DownloadHelperTest.cc \ DNSCacheTest.cc DownloadHelperTest.cc SequentialPickerTest.cc \
SequentialPickerTest.cc RarestPieceSelectorTest.cc \ RarestPieceSelectorTest.cc PieceStatManTest.cc \
PieceStatManTest.cc InOrderPieceSelector.h \ InOrderPieceSelector.h LongestSequencePieceSelectorTest.cc \
LongestSequencePieceSelectorTest.cc a2algoTest.cc \ a2algoTest.cc bitfieldTest.cc BDETest.cc \
bitfieldTest.cc BDETest.cc DownloadContextTest.cc \ DownloadContextTest.cc $(am__append_1) $(am__append_2) \
$(am__append_1) $(am__append_2) $(am__append_3) \ $(am__append_3) $(am__append_4) $(am__append_5) \
$(am__append_4) $(am__append_5) $(am__append_6) \ $(am__append_6) $(am__append_7)
$(am__append_7)
#aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64 #aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
#aria2c_LDFLAGS = ${CPPUNIT_LIBS} #aria2c_LDFLAGS = ${CPPUNIT_LIBS}
@ -759,6 +757,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHTTokenTrackerTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHTTokenTrackerTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHTUnknownMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHTUnknownMessageTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHTUtilTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHTUtilTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DNSCacheTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultAuthResolverTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultAuthResolverTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtAnnounceTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtAnnounceTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtMessageDispatcherTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtMessageDispatcherTest.Po@am__quote@
@ -830,7 +829,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShareRatioSeedCriteriaTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShareRatioSeedCriteriaTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SharedHandleTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SharedHandleTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SignatureTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SignatureTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SimpleDNSCacheTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SingleFileAllocationIteratorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SingleFileAllocationIteratorTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SingletonHolderTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SingletonHolderTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SocketCoreTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SocketCoreTest.Po@am__quote@

View File

@ -1,35 +0,0 @@
#include "DNSCache.h"
#include <iostream>
#include <cppunit/extensions/HelperMacros.h>
#include "Exception.h"
#include "Util.h"
namespace aria2 {
class SimpleDNSCacheTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(SimpleDNSCacheTest);
CPPUNIT_TEST(testFind);
CPPUNIT_TEST_SUITE_END();
public:
void testFind();
};
CPPUNIT_TEST_SUITE_REGISTRATION(SimpleDNSCacheTest);
void SimpleDNSCacheTest::testFind()
{
SimpleDNSCache cache;
cache.put("host1", "192.168.0.1");
cache.put("host2", "192.168.1.2");
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), cache.find("host1"));
CPPUNIT_ASSERT_EQUAL(std::string("192.168.1.2"), cache.find("host2"));
CPPUNIT_ASSERT_EQUAL(std::string(""), cache.find("host3"));
}
} // namespace aria2