Explorar el Código

2008-05-08 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	Rewritten name resolver. Now async DNS can be disabled by 
--async-dns
	option.
	The asynchronous DNS is not capable of IPv6 yet.
	By disabling asynchronous DNS, aria2 is IPv6 enabled 
application, at
	least for HTTP download.
	* src/AbstractCommand.cc
	* src/AbstractCommand.h
	* src/AsyncNameResolver.cc
	* src/AsyncNameResolver.h
	* src/DHTEntryPointNameResolveCommand.cc
	* src/DHTEntryPointNameResolveCommand.h
	* src/DownloadEngine.cc
	* src/DownloadEngine.h
	* src/FtpInitiateConnectionCommand.cc
	* src/FtpInitiateConnectionCommand.h
	* src/HelpItemFactory.cc
	* src/HttpInitiateConnectionCommand.cc
	* src/HttpInitiateConnectionCommand.h
	* src/InitiateConnectionCommand.cc
	* src/InitiateConnectionCommand.h
	* src/Makefile.am
	* src/Makefile.in
	* src/NameResolver.cc
	* src/NameResolver.h
	* src/OptionHandlerFactory.cc
	* src/SocketCore.cc
	* src/SocketCore.h
	* src/Util.cc
	* src/Util.h
	* src/option_processing.cc
	* src/prefs.h
	* src/usage_text.h
Tatsuhiro Tsujikawa hace 17 años
padre
commit
d52bce74d3

+ 35 - 0
ChangeLog

@@ -1,3 +1,38 @@
+2008-05-08  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	Rewritten name resolver. Now async DNS can be disabled by --async-dns
+	option.
+	The asynchronous DNS is not capable of IPv6 yet.
+	By disabling asynchronous DNS, aria2 is IPv6 enabled application, at
+	least for HTTP download.
+	* src/AbstractCommand.cc
+	* src/AbstractCommand.h
+	* src/AsyncNameResolver.cc
+	* src/AsyncNameResolver.h
+	* src/DHTEntryPointNameResolveCommand.cc
+	* src/DHTEntryPointNameResolveCommand.h
+	* src/DownloadEngine.cc
+	* src/DownloadEngine.h
+	* src/FtpInitiateConnectionCommand.cc
+	* src/FtpInitiateConnectionCommand.h
+	* src/HelpItemFactory.cc
+	* src/HttpInitiateConnectionCommand.cc
+	* src/HttpInitiateConnectionCommand.h
+	* src/InitiateConnectionCommand.cc
+	* src/InitiateConnectionCommand.h
+	* src/Makefile.am
+	* src/Makefile.in
+	* src/NameResolver.cc
+	* src/NameResolver.h
+	* src/OptionHandlerFactory.cc
+	* src/SocketCore.cc
+	* src/SocketCore.h
+	* src/Util.cc
+	* src/Util.h
+	* src/option_processing.cc
+	* src/prefs.h
+	* src/usage_text.h
+
 2008-05-07  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	Updated man page: --quiet, --header were added.

+ 55 - 44
src/AbstractCommand.cc

@@ -46,8 +46,9 @@
 #include "DownloadFailureException.h"
 #include "InitiateConnectionCommandFactory.h"
 #include "SleepCommand.h"
-#include "NameResolver.h"
-#include "DNSCache.h"
+#ifdef ENABLE_ASYNC_DNS
+#include "AsyncNameResolver.h"
+#endif // ENABLE_ASYNC_DNS
 #include "StreamCheckIntegrityEntry.h"
 #include "PieceStorage.h"
 #include "Socket.h"
@@ -57,6 +58,8 @@
 
 namespace aria2 {
 
+// TODO $$$$$$$$$$$ fix two nearly identical constructor. $$$$$$$$$$$$$$
+// Modify two constructor at the same time!
 AbstractCommand::AbstractCommand(int32_t cuid,
 				 const SharedHandle<Request>& req,
 				 RequestGroup* requestGroup,
@@ -89,6 +92,9 @@ AbstractCommand::AbstractCommand(int32_t cuid,
 AbstractCommand::~AbstractCommand() {
   disableReadCheckSocket();
   disableWriteCheckSocket();
+#ifdef ENABLE_ASYNC_DNS
+  disableNameResolverCheck(_asyncNameResolver);
+#endif // ENABLE_ASYNC_DNS
   _requestGroup->decreaseStreamConnection();
 }
 
@@ -257,59 +263,64 @@ void AbstractCommand::setWriteCheckSocket(const SocketHandle& socket) {
   }
 }
 
-bool AbstractCommand::resolveHostname(const std::string& hostname,
-				      const NameResolverHandle& resolver) {
-  std::string ipaddr = DNSCacheSingletonHolder::instance()->find(hostname);
-  if(ipaddr.empty()) {
 #ifdef ENABLE_ASYNC_DNS
-    switch(resolver->getStatus()) {
-    case NameResolver::STATUS_READY:
-      logger->info(MSG_RESOLVING_HOSTNAME, cuid, hostname.c_str());
-      resolver->resolve(hostname);
-      setNameResolverCheck(resolver);
-      return false;
-    case NameResolver::STATUS_SUCCESS:
-      logger->info(MSG_NAME_RESOLUTION_COMPLETE, cuid,
-		   hostname.c_str(), resolver->getAddrString().c_str());
-      DNSCacheSingletonHolder::instance()->put(hostname, resolver->getAddrString());
-      return true;
-      break;
-    case NameResolver::STATUS_ERROR:
-      throw DlAbortEx(StringFormat(MSG_NAME_RESOLUTION_FAILED, cuid,
-				   hostname.c_str(),
-				   resolver->getError().c_str()).str());
-    default:
-      return false;
-    }
-#else
-    logger->info(MSG_RESOLVING_HOSTNAME, cuid, hostname.c_str());
-    resolver->resolve(hostname);
+
+bool AbstractCommand::isAsyncNameResolverInitialized() const
+{
+  return !_asyncNameResolver.isNull();
+}
+
+void AbstractCommand::initAsyncNameResolver(const std::string& hostname)
+{
+  _asyncNameResolver.reset(new AsyncNameResolver());
+  logger->info(MSG_RESOLVING_HOSTNAME, cuid, hostname.c_str());
+  _asyncNameResolver->resolve(hostname);
+  setNameResolverCheck(_asyncNameResolver);
+}
+
+bool AbstractCommand::asyncResolveHostname()
+{
+  switch(_asyncNameResolver->getStatus()) {
+  case AsyncNameResolver::STATUS_SUCCESS:
     logger->info(MSG_NAME_RESOLUTION_COMPLETE, cuid,
-		 hostname.c_str(), resolver->getAddrString().c_str());
-    DNSCacheSingletonHolder::instance()->put(hostname, resolver->getAddrString());
-    return true;
-#endif // ENABLE_ASYNC_DNS
-  } else {
-    logger->info(MSG_DNS_CACHE_HIT, cuid,
-		 hostname.c_str(), ipaddr.c_str());
-    resolver->setAddr(ipaddr);
+		 _asyncNameResolver->getHostname().c_str(),
+		 _asyncNameResolver->getResolvedAddresses().front().c_str());
     return true;
+    break;
+  case AsyncNameResolver::STATUS_ERROR:
+    throw DlAbortEx(StringFormat(MSG_NAME_RESOLUTION_FAILED, cuid,
+				 _asyncNameResolver->getHostname().c_str(),
+				 _asyncNameResolver->getError().c_str()).str());
+  default:
+    return false;
   }
 }
 
-#ifdef ENABLE_ASYNC_DNS
-void AbstractCommand::setNameResolverCheck(const NameResolverHandle& resolver) {
-  nameResolverCheck = true;
-  e->addNameResolverCheck(resolver, this);
+const std::deque<std::string>& AbstractCommand::getResolvedAddresses()
+{
+  return _asyncNameResolver->getResolvedAddresses();
+}
+
+void AbstractCommand::setNameResolverCheck
+(const SharedHandle<AsyncNameResolver>& resolver) {
+  if(!resolver.isNull()) {
+    nameResolverCheck = true;
+    e->addNameResolverCheck(resolver, this);
+  }
 }
 
-void AbstractCommand::disableNameResolverCheck(const NameResolverHandle& resolver) {
-  nameResolverCheck = false;
-  e->deleteNameResolverCheck(resolver, this);
+void AbstractCommand::disableNameResolverCheck
+(const SharedHandle<AsyncNameResolver>& resolver) {
+  if(!resolver.isNull()) {
+    nameResolverCheck = false;
+    e->deleteNameResolverCheck(resolver, this);
+  }
 }
 
 bool AbstractCommand::nameResolveFinished() const {
-  return false;
+  return
+    _asyncNameResolver->getStatus() ==  AsyncNameResolver::STATUS_SUCCESS ||
+    _asyncNameResolver->getStatus() == AsyncNameResolver::STATUS_ERROR;
 }
 #endif // ENABLE_ASYNC_DNS
 

+ 24 - 8
src/AbstractCommand.h

@@ -46,9 +46,11 @@ class Request;
 class DownloadEngine;
 class RequestGroup;
 class Segment;
-class NameResolver;
 class Exception;
 class SocketCore;
+#ifdef ENABLE_ASYNC_DNS
+class AsyncNameResolver;
+#endif // ENABLE_ASYNC_DNS
 
 class AbstractCommand : public Command, public RequestGroupAware {
 private:
@@ -60,6 +62,18 @@ protected:
   SharedHandle<SocketCore> socket;
   std::deque<SharedHandle<Segment> > _segments;
 
+#ifdef ENABLE_ASYNC_DNS
+  SharedHandle<AsyncNameResolver> _asyncNameResolver;
+
+  bool isAsyncNameResolverInitialized() const;
+
+  void initAsyncNameResolver(const std::string& hostname);
+
+  bool asyncResolveHostname();
+
+  const std::deque<std::string>& getResolvedAddresses();
+#endif // ENABLE_ASYNC_DNS
+
   void tryReserved();
   virtual bool prepareForRetry(time_t wait);
   virtual void onAbort();
@@ -69,13 +83,7 @@ protected:
   void setWriteCheckSocket(const SharedHandle<SocketCore>& socket);
   void disableReadCheckSocket();
   void disableWriteCheckSocket();
-  bool resolveHostname(const std::string& hostname,
-		       const SharedHandle<NameResolver>& nameResolver);
-#ifdef ENABLE_ASYNC_DNS
-  void setNameResolverCheck(const SharedHandle<NameResolver>& resolver);
-  void disableNameResolverCheck(const SharedHandle<NameResolver>& resolver);
-  virtual bool nameResolveFinished() const;
-#endif // ENABLE_ASYNC_DNS
+
   void setTimeout(time_t timeout) { this->timeout = timeout; }
 
   void prepareForNextAction(Command* nextCommand = 0);
@@ -87,6 +95,14 @@ private:
   SharedHandle<SocketCore> writeCheckTarget;
   bool nameResolverCheck;
 
+#ifdef ENABLE_ASYNC_DNS
+
+  void setNameResolverCheck(const SharedHandle<AsyncNameResolver>& resolver);
+
+  void disableNameResolverCheck(const SharedHandle<AsyncNameResolver>& resolver);
+  bool nameResolveFinished() const;
+
+#endif // ENABLE_ASYNC_DNS
 public:
   AbstractCommand(int32_t cuid, const SharedHandle<Request>& req,
 		  RequestGroup* requestGroup, DownloadEngine* e,

+ 137 - 0
src/AsyncNameResolver.cc

@@ -0,0 +1,137 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 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 "AsyncNameResolver.h"
+#include "Util.h"
+#include <cstring>
+
+namespace aria2 {
+
+#ifdef HAVE_LIBCARES1_5
+void callback(void* arg, int status, int timeouts, struct hostent* host)
+#else
+void callback(void* arg, int status, struct hostent* host)
+#endif // HAVE_LIBCARES1_5
+{
+  AsyncNameResolver* resolverPtr = reinterpret_cast<AsyncNameResolver*>(arg);
+#ifdef HAVE_LIBARES
+  // This block is required since the assertion in ares_strerror fails
+  // if status = ARES_EDESTRUCTION is passed to ares_strerror as 1st argument.
+  // This does not happen in c-ares.
+  if(status == ARES_EDESTRUCTION) {
+    // we simply return in this case.
+    return;
+  }
+#endif
+  if(status != ARES_SUCCESS) {
+#ifdef HAVE_LIBCARES
+    resolverPtr->error = ares_strerror(status);
+#else
+    resolverPtr->error = ares_strerror(status, 0);
+#endif // HAVE_LIBCARES
+    resolverPtr->status = AsyncNameResolver::STATUS_ERROR;
+    return;
+  }
+  for(char** ap = host->h_addr_list; *ap; ++ap) {
+    resolverPtr->_resolvedAddresses.push_back
+      (inet_ntoa(*reinterpret_cast<struct in_addr*>(*ap)));
+  }
+  resolverPtr->status = AsyncNameResolver::STATUS_SUCCESS;
+}
+
+AsyncNameResolver::AsyncNameResolver():
+  status(STATUS_READY)
+{
+  // TODO evaluate return value
+  ares_init(&channel);
+}
+
+AsyncNameResolver::~AsyncNameResolver()
+{
+  ares_destroy(channel);
+}
+
+void AsyncNameResolver::resolve(const std::string& name)
+{
+  _hostname = name;
+  status = STATUS_QUERYING;
+  ares_gethostbyname(channel, name.c_str(), AF_INET, callback, this);
+}
+
+const std::deque<std::string>& AsyncNameResolver::getResolvedAddresses() const
+{
+  return _resolvedAddresses;
+}
+
+const std::string& AsyncNameResolver::getError() const
+{
+  return error;
+}
+
+AsyncNameResolver::STATUS AsyncNameResolver::getStatus() const
+{
+  return status;
+}
+
+int AsyncNameResolver::getFds(fd_set* rfdsPtr, fd_set* wfdsPtr) const
+{
+  return ares_fds(channel, rfdsPtr, wfdsPtr);
+}
+
+void AsyncNameResolver::process(fd_set* rfdsPtr, fd_set* wfdsPtr)
+{
+  ares_process(channel, rfdsPtr, wfdsPtr);
+}
+
+bool AsyncNameResolver::operator==(const AsyncNameResolver& resolver) const
+{
+  return this == &resolver;
+}
+
+void AsyncNameResolver::reset()
+{
+  _hostname = "";
+  _resolvedAddresses.clear();
+  status = STATUS_READY;
+  ares_destroy(channel);
+  // TODO evaluate return value
+  ares_init(&channel);
+}
+
+const std::string& AsyncNameResolver::getHostname() const
+{
+  return _hostname;
+}
+
+} // namespace aria2

+ 103 - 0
src/AsyncNameResolver.h

@@ -0,0 +1,103 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 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 _D_ASYNC_NAME_RESOLVER_H_
+#define _D_ASYNC_NAME_RESOLVER_H_
+
+#include "common.h"
+#include "SharedHandle.h"
+#include "a2netcompat.h"
+#include <string>
+#include <deque>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <ares.h>
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+namespace aria2 {
+
+class AsyncNameResolver {
+#ifdef HAVE_LIBCARES1_5
+  friend void callback(void* arg, int status, int timeouts, struct hostent* host);
+#else
+  friend void callback(void* arg, int status, struct hostent* host);
+#endif // HAVE_LIBCARES1_5
+
+public:
+  enum STATUS {
+    STATUS_READY,
+    STATUS_QUERYING,
+    STATUS_SUCCESS,
+    STATUS_ERROR,
+  };
+private:
+  STATUS status;
+  ares_channel channel;
+
+  std::deque<std::string> _resolvedAddresses;
+  std::string error;
+  std::string _hostname;
+public:
+  AsyncNameResolver();
+
+  ~AsyncNameResolver();
+
+  void resolve(const std::string& name);
+
+  const std::deque<std::string>& getResolvedAddresses() const;
+
+  const std::string& getError() const;
+
+  STATUS getStatus() const;
+
+  int getFds(fd_set* rfdsPtr, fd_set* wfdsPtr) const;
+
+  void process(fd_set* rfdsPtr, fd_set* wfdsPtr);
+
+  bool operator==(const AsyncNameResolver& resolver) const;
+
+  void setAddr(const std::string& addrString);
+
+  void reset();
+
+  const std::string& getHostname() const;
+};
+
+} // namespace aria2
+
+#endif // _D_ASYNC_NAME_RESOLVER_H_

+ 63 - 57
src/DHTEntryPointNameResolveCommand.cc

@@ -34,8 +34,10 @@
 /* copyright --> */
 #include "DHTEntryPointNameResolveCommand.h"
 #include "DownloadEngine.h"
+#ifdef ENABLE_ASYNC_DNS
+#include "AsyncNameResolver.h"
+#endif // ENABLE_ASYNC_DNS
 #include "NameResolver.h"
-#include "DNSCache.h"
 #include "DlAbortEx.h"
 #include "prefs.h"
 #include "message.h"
@@ -55,7 +57,6 @@ namespace aria2 {
 DHTEntryPointNameResolveCommand::DHTEntryPointNameResolveCommand(int32_t cuid, DownloadEngine* e, const std::deque<std::pair<std::string, uint16_t> >& entryPoints):
   Command(cuid),
   _e(e),
-  _resolver(new NameResolver()),
   _entryPoints(entryPoints),
   _bootstrapEnabled(false)
 {}
@@ -72,37 +73,53 @@ bool DHTEntryPointNameResolveCommand::execute()
   if(_e->_requestGroupMan->downloadFinished() || _e->isHaltRequested()) {
     return true;
   }
+#ifdef ENABLE_ASYNC_DNS
+  if(_resolver.isNull()) {
+    _resolver.reset(new AsyncNameResolver());
+  }
+#endif // ENABLE_ASYNC_DNS
   try {
-    while(_entryPoints.size()) {
-      std::string hostname = _entryPoints.front().first;
-      try {
-	if(Util::isNumbersAndDotsNotation(hostname)) {
-	  std::pair<std::string, uint16_t> p(hostname,
-					     _entryPoints.front().second);
-	  _resolvedEntryPoints.push_back(p);
-	  _entryPoints.erase(_entryPoints.begin());
-	  addPingTask(p);
-	} else {
+#ifdef ENABLE_ASYNC_DNS
+    if(_e->option->getAsBool(PREF_ASYNC_DNS)) {
+      while(_entryPoints.size()) {
+	std::string hostname = _entryPoints.front().first;
+	try {
 	  if(resolveHostname(hostname, _resolver)) {
-	    hostname = _resolver->getAddrString();
-	    _resolver->reset();
+	    hostname = _resolver->getResolvedAddresses().front();
 	    std::pair<std::string, uint16_t> p(hostname,
 					       _entryPoints.front().second);
 	    _resolvedEntryPoints.push_back(p);
-	    _entryPoints.erase(_entryPoints.begin());
 	    addPingTask(p);
 	  } else {
 	    _e->commands.push_back(this);
 	    return false;
 	  }
+	} catch(RecoverableException& e) {
+	  logger->error(EX_EXCEPTION_CAUGHT, e);
 	}
-      } catch(RecoverableException& e) {
-	logger->error(EX_EXCEPTION_CAUGHT, e);
-	_entryPoints.erase(_entryPoints.begin());
 	_resolver->reset();
+	_entryPoints.erase(_entryPoints.begin());
+      }
+    } else
+#endif // ENABLE_ASYNC_DNS
+      {
+	NameResolver res;
+	res.setSocktype(SOCK_DGRAM);
+	while(_entryPoints.size()) {
+	  std::string hostname = _entryPoints.front().first;
+	  try {
+	    std::deque<std::string> addrs(res.resolve(hostname));
+	  
+	    std::pair<std::string, uint16_t> p(addrs.front(),
+					       _entryPoints.front().second);
+	    _resolvedEntryPoints.push_back(p);
+	    addPingTask(p);
+	  } catch(RecoverableException& e) {
+	    logger->error(EX_EXCEPTION_CAUGHT, e);
+	  }
+	  _entryPoints.erase(_entryPoints.begin());
+	}
       }
-    }
-
     if(_bootstrapEnabled && _resolvedEntryPoints.size()) {
       _taskQueue->addPeriodicTask1(_taskFactory->createNodeLookupTask(_localNode->getID()));
       _taskQueue->addPeriodicTask1(_taskFactory->createBucketRefreshTask());
@@ -122,54 +139,43 @@ void DHTEntryPointNameResolveCommand::addPingTask(const std::pair<std::string, u
   _taskQueue->addPeriodicTask1(_taskFactory->createPingTask(entryNode, 10));
 }
 
-bool DHTEntryPointNameResolveCommand::resolveHostname(const std::string& hostname,
-						      const NameResolverHandle& resolver)
-{
-  std::string ipaddr = DNSCacheSingletonHolder::instance()->find(hostname);
-  if(ipaddr.empty()) {
 #ifdef ENABLE_ASYNC_DNS
-    switch(resolver->getStatus()) {
-    case NameResolver::STATUS_READY:
-      logger->info(MSG_RESOLVING_HOSTNAME, cuid, hostname.c_str());
-      resolver->resolve(hostname);
-      setNameResolverCheck(resolver);
-      return false;
-    case NameResolver::STATUS_SUCCESS:
-      logger->info(MSG_NAME_RESOLUTION_COMPLETE, cuid,
-		   hostname.c_str(), resolver->getAddrString().c_str());
-      DNSCacheSingletonHolder::instance()->put(hostname, resolver->getAddrString());
-      return true;
-      break;
-    case NameResolver::STATUS_ERROR:
-      throw DlAbortEx
-	(StringFormat(MSG_NAME_RESOLUTION_FAILED, cuid,
-		      hostname.c_str(),
-		      resolver->getError().c_str()).str());
-    default:
-      return false;
-    }
-#else
+
+bool DHTEntryPointNameResolveCommand::resolveHostname
+(const std::string& hostname,
+ const SharedHandle<AsyncNameResolver>& resolver)
+{
+  switch(resolver->getStatus()) {
+  case AsyncNameResolver::STATUS_READY:
     logger->info(MSG_RESOLVING_HOSTNAME, cuid, hostname.c_str());
     resolver->resolve(hostname);
+    setNameResolverCheck(resolver);
+    return false;
+  case AsyncNameResolver::STATUS_SUCCESS:
     logger->info(MSG_NAME_RESOLUTION_COMPLETE, cuid,
-		 hostname.c_str(), resolver->getAddrString().c_str());
-    DNSCacheSingletonHolder::instance()->put(hostname, resolver->getAddrString());
-    return true;
-#endif // ENABLE_ASYNC_DNS
-  } else {
-    logger->info(MSG_DNS_CACHE_HIT, cuid,
-		 hostname.c_str(), ipaddr.c_str());
-    resolver->setAddr(ipaddr);
+		 resolver->getHostname().c_str(),
+		 resolver->getResolvedAddresses().front().c_str());
     return true;
+    break;
+  case AsyncNameResolver::STATUS_ERROR:
+    throw DlAbortEx
+      (StringFormat(MSG_NAME_RESOLUTION_FAILED, cuid,
+		    hostname.c_str(),
+		    resolver->getError().c_str()).str());
+  default:
+    return false;
   }
 }
 
-#ifdef ENABLE_ASYNC_DNS
-void DHTEntryPointNameResolveCommand::setNameResolverCheck(const SharedHandle<NameResolver>& resolver) {
+void DHTEntryPointNameResolveCommand::setNameResolverCheck
+(const SharedHandle<AsyncNameResolver>& resolver)
+{
   _e->addNameResolverCheck(resolver, this);
 }
 
-void DHTEntryPointNameResolveCommand::disableNameResolverCheck(const SharedHandle<NameResolver>& resolver) {
+void DHTEntryPointNameResolveCommand::disableNameResolverCheck
+(const SharedHandle<AsyncNameResolver>& resolver)
+{
   _e->deleteNameResolverCheck(resolver, this);
 }
 #endif // ENABLE_ASYNC_DNS

+ 11 - 5
src/DHTEntryPointNameResolveCommand.h

@@ -47,13 +47,17 @@ class DHTTaskFactory;
 class DHTRoutingTable;
 class DHTNode;
 class DownloadEngine;
-class NameResolver;
+#ifdef ENABLE_ASYNC_DNS
+class AsyncNameResolver;
+#endif // ENABLE_ASYNC_DNS
 
 class DHTEntryPointNameResolveCommand:public Command {
 protected:
   DownloadEngine* _e;
 private:
-  SharedHandle<NameResolver> _resolver;
+#ifdef ENABLE_ASYNC_DNS
+  SharedHandle<AsyncNameResolver> _resolver;
+#endif // ENABLE_ASYNC_DNS
 
   SharedHandle<DHTTaskQueue> _taskQueue;
 
@@ -71,12 +75,14 @@ private:
 
   void addPingTask(const std::pair<std::string, uint16_t>& addr);
 
+#ifdef ENABLE_ASYNC_DNS
   bool resolveHostname(const std::string& hostname,
-		       const SharedHandle<NameResolver>& resolver);
+		       const SharedHandle<AsyncNameResolver>& resolver);
 
-  void setNameResolverCheck(const SharedHandle<NameResolver>& resolver);
+  void setNameResolverCheck(const SharedHandle<AsyncNameResolver>& resolver);
 
-  void disableNameResolverCheck(const SharedHandle<NameResolver>& resolver);
+  void disableNameResolverCheck(const SharedHandle<AsyncNameResolver>& resolver);
+#endif // ENABLE_ASYNC_DNS
 
 public:
   DHTEntryPointNameResolveCommand(int32_t cuid, DownloadEngine* e,

+ 41 - 22
src/DownloadEngine.cc

@@ -33,7 +33,9 @@
  */
 /* copyright --> */
 #include "DownloadEngine.h"
-#include "NameResolver.h"
+#ifdef ENABLE_ASYNC_DNS
+#include "AsyncNameResolver.h"
+#endif // ENABLE_ASYNC_DNS
 #include "StatCalc.h"
 #include "RequestGroup.h"
 #include "RequestGroupMan.h"
@@ -73,11 +75,12 @@ bool SocketEntry::operator==(const SocketEntry& entry)
 }
 
 #ifdef ENABLE_ASYNC_DNS
-NameResolverEntry::NameResolverEntry(const NameResolverHandle& nameResolver,
-					     Command* command):
+AsyncNameResolverEntry::AsyncNameResolverEntry
+(const SharedHandle<AsyncNameResolver>& nameResolver,
+ Command* command):
   nameResolver(nameResolver), command(command) {}
 
-bool NameResolverEntry::operator==(const NameResolverEntry& entry)
+bool AsyncNameResolverEntry::operator==(const AsyncNameResolverEntry& entry)
 {
   return nameResolver == entry.nameResolver &&
     command == entry.command;
@@ -164,9 +167,9 @@ void DownloadEngine::waitData() {
   memcpy(&wfds, &wfdset, sizeof(fd_set));
   
 #ifdef ENABLE_ASYNC_DNS
-  for(NameResolverEntries::iterator itr = nameResolverEntries.begin();
+  for(AsyncNameResolverEntries::iterator itr = nameResolverEntries.begin();
       itr != nameResolverEntries.end(); ++itr) {
-    NameResolverEntry& entry = *itr;
+    AsyncNameResolverEntry& entry = *itr;
     int fd = entry.nameResolver->getFds(&rfds, &wfds);
     // TODO force error if fd == 0
     if(fdmax < fd) {
@@ -189,13 +192,13 @@ void DownloadEngine::waitData() {
     }
   }
 #ifdef ENABLE_ASYNC_DNS
-  for(NameResolverEntries::iterator itr = nameResolverEntries.begin();
+  for(AsyncNameResolverEntries::iterator itr = nameResolverEntries.begin();
       itr != nameResolverEntries.end(); ++itr) {
-    NameResolverEntry& entry = *itr;
+    AsyncNameResolverEntry& entry = *itr;
     entry.nameResolver->process(&rfds, &wfds);
     switch(entry.nameResolver->getStatus()) {
-    case NameResolver::STATUS_SUCCESS:
-    case NameResolver::STATUS_ERROR:
+    case AsyncNameResolver::STATUS_SUCCESS:
+    case AsyncNameResolver::STATUS_ERROR:
       entry.command->setStatusActive();
       break;
     default:
@@ -323,12 +326,13 @@ void DownloadEngine::addCommand(const Commands& commands)
 }
 
 #ifdef ENABLE_ASYNC_DNS
-bool DownloadEngine::addNameResolverCheck(const NameResolverHandle& resolver,
-					  Command* command) {
-  NameResolverEntry entry(resolver, command);
-  NameResolverEntries::iterator itr = std::find(nameResolverEntries.begin(),
-						nameResolverEntries.end(),
-						entry);
+bool DownloadEngine::addNameResolverCheck
+(const SharedHandle<AsyncNameResolver>& resolver,
+ Command* command)
+{
+  AsyncNameResolverEntry entry(resolver, command);
+  AsyncNameResolverEntries::iterator itr =
+    std::find(nameResolverEntries.begin(), nameResolverEntries.end(), entry);
   if(itr == nameResolverEntries.end()) {
     nameResolverEntries.push_back(entry);
     return true;
@@ -337,12 +341,13 @@ bool DownloadEngine::addNameResolverCheck(const NameResolverHandle& resolver,
   }
 }
 
-bool DownloadEngine::deleteNameResolverCheck(const NameResolverHandle& resolver,
-					     Command* command) {
-  NameResolverEntry entry(resolver, command);
-  NameResolverEntries::iterator itr = std::find(nameResolverEntries.begin(),
-						nameResolverEntries.end(),
-						entry);
+bool DownloadEngine::deleteNameResolverCheck
+(const SharedHandle<AsyncNameResolver>& resolver,
+ Command* command)
+{
+  AsyncNameResolverEntry entry(resolver, command);
+  AsyncNameResolverEntries::iterator itr =
+    std::find(nameResolverEntries.begin(), nameResolverEntries.end(), entry);
   if(itr == nameResolverEntries.end()) {
     return false;
   } else {
@@ -388,4 +393,18 @@ DownloadEngine::popPooledSocket(const std::string& ipaddr, uint16_t port)
   }
 }
 
+SharedHandle<SocketCore>
+DownloadEngine::popPooledSocket
+(const std::deque<std::string>& ipaddrs, uint16_t port)
+{
+  for(std::deque<std::string>::const_iterator i = ipaddrs.begin();
+      i != ipaddrs.end(); ++i) {
+    SharedHandle<SocketCore> s = popPooledSocket(*i, port);
+    if(!s.isNull()) {
+      return s;
+    }
+  }
+  return SharedHandle<SocketCore>();
+}
+
 } // namespace aria2

+ 17 - 11
src/DownloadEngine.h

@@ -38,15 +38,17 @@
 #include "common.h"
 #include "SharedHandle.h"
 #include "Command.h"
+#include "a2netcompat.h"
 #include <deque>
 #include <map>
-#include "a2netcompat.h"
 
 namespace aria2 {
 
 class Logger;
 class Option;
-class NameResolver;
+#ifdef ENABLE_ASYNC_DNS
+class AsyncNameResolver;
+#endif // ENABLE_ASYNC_DNS
 class RequestGroupMan;
 class FileAllocationMan;
 class StatCalc;
@@ -74,18 +76,18 @@ public:
 typedef std::deque<SocketEntry> SocketEntries;
 
 #ifdef ENABLE_ASYNC_DNS
-class NameResolverEntry {
+class AsyncNameResolverEntry {
 public:
-  SharedHandle<NameResolver> nameResolver;
+  SharedHandle<AsyncNameResolver> nameResolver;
   Command* command;
 public:
-  NameResolverEntry(const SharedHandle<NameResolver>& nameResolver,
-		    Command* command);
+  AsyncNameResolverEntry(const SharedHandle<AsyncNameResolver>& nameResolver,
+			 Command* command);
 
-  bool operator==(const NameResolverEntry& entry);
+  bool operator==(const AsyncNameResolverEntry& entry);
 };
 
-typedef std::deque<NameResolverEntry> NameResolverEntries;
+typedef std::deque<AsyncNameResolverEntry> AsyncNameResolverEntries;
 #endif // ENABLE_ASYNC_DNS
 
 class DownloadEngine {
@@ -93,7 +95,7 @@ private:
   void waitData();
   SocketEntries socketEntries;
 #ifdef ENABLE_ASYNC_DNS
-  NameResolverEntries nameResolverEntries;
+  AsyncNameResolverEntries nameResolverEntries;
 #endif // ENABLE_ASYNC_DNS
   fd_set rfdset;
   fd_set wfdset;
@@ -152,9 +154,9 @@ public:
   bool deleteSocketForWriteCheck(const SharedHandle<SocketCore>& socket,
 				 Command* command);
 #ifdef ENABLE_ASYNC_DNS
-  bool addNameResolverCheck(const SharedHandle<NameResolver>& resolver,
+  bool addNameResolverCheck(const SharedHandle<AsyncNameResolver>& resolver,
 			    Command* command);
-  bool deleteNameResolverCheck(const SharedHandle<NameResolver>& resolver,
+  bool deleteNameResolverCheck(const SharedHandle<AsyncNameResolver>& resolver,
 			       Command* command);
 #endif // ENABLE_ASYNC_DNS
 
@@ -180,6 +182,10 @@ public:
 
   SharedHandle<SocketCore> popPooledSocket(const std::string& ipaddr,
 					   uint16_t port);
+
+
+  SharedHandle<SocketCore>
+  popPooledSocket(const std::deque<std::string>& ipaddrs, uint16_t port);
 };
 
 typedef SharedHandle<DownloadEngine> DownloadEngineHandle;

+ 20 - 57
src/FtpInitiateConnectionCommand.cc

@@ -33,9 +33,7 @@
  */
 /* copyright --> */
 #include "FtpInitiateConnectionCommand.h"
-#include "NameResolver.h"
 #include "DownloadEngine.h"
-#include "RequestGroup.h"
 #include "Option.h"
 #include "Request.h"
 #include "FtpNegotiationCommand.h"
@@ -47,58 +45,35 @@
 #include "Logger.h"
 #include "message.h"
 #include "prefs.h"
-#include "Util.h"
 #include "HttpConnection.h"
 #include "Socket.h"
 
 namespace aria2 {
 
-FtpInitiateConnectionCommand::FtpInitiateConnectionCommand(int cuid,
-							   const RequestHandle& req,
-							   RequestGroup* requestGroup,
-							   DownloadEngine* e)
-  :AbstractCommand(cuid, req, requestGroup, e),
-   nameResolver(new NameResolver())
-{
-  setTimeout(e->option->getAsInt(PREF_DNS_TIMEOUT));
-  setStatus(Command::STATUS_ONESHOT_REALTIME);
-  disableReadCheckSocket();
-  disableWriteCheckSocket();
-}
+FtpInitiateConnectionCommand::FtpInitiateConnectionCommand
+(int cuid,
+ const RequestHandle& req,
+ RequestGroup* requestGroup,
+ DownloadEngine* e)
+  :InitiateConnectionCommand(cuid, req, requestGroup, e) {}
 
-FtpInitiateConnectionCommand::~FtpInitiateConnectionCommand() {
-#ifdef ENABLE_ASYNC_DNS
-  disableNameResolverCheck(nameResolver);
-#endif // ENABLE_ASYNC_DNS
-}
+FtpInitiateConnectionCommand::~FtpInitiateConnectionCommand() {}
 
-bool FtpInitiateConnectionCommand::executeInternal() {
-  std::string hostname;
-  if(useHttpProxy()) {
-    hostname = e->option->get(PREF_HTTP_PROXY_HOST);
-  } else {
-    hostname = req->getHost();
-  }
-  if(!Util::isNumbersAndDotsNotation(hostname)) {
-    if(resolveHostname(hostname, nameResolver)) {
-      hostname = nameResolver->getAddrString();
-    } else {
-      e->commands.push_back(this);
-      return false;
-    }
-  }
+Command* FtpInitiateConnectionCommand::createNextCommand
+(const std::deque<std::string>& resolvedAddresses)
+{
   Command* command;
-  if(useHttpProxy()) {
+  if(useHTTPProxy()) {
     logger->info(MSG_CONNECTING_TO_SERVER, cuid,
 		 e->option->get(PREF_HTTP_PROXY_HOST).c_str(),
 		 e->option->getAsInt(PREF_HTTP_PROXY_PORT));
-    socket->establishConnection(hostname,
+    socket->establishConnection(resolvedAddresses.front(),
 				e->option->getAsInt(PREF_HTTP_PROXY_PORT));
     
-    if(useHttpProxyGet()) {
+    if(useHTTPProxyGet()) {
       SharedHandle<HttpConnection> hc(new HttpConnection(cuid, socket, e->option));
       command = new HttpRequestCommand(cuid, req, _requestGroup, hc, e, socket);
-    } else if(useHttpProxyConnect()) {
+    } else if(useHTTPProxyConnect()) {
       command = new FtpTunnelRequestCommand(cuid, req, _requestGroup, e, socket);
     } else {
       // TODO
@@ -107,30 +82,18 @@ bool FtpInitiateConnectionCommand::executeInternal() {
   } else {
     logger->info(MSG_CONNECTING_TO_SERVER, cuid, req->getHost().c_str(),
 		 req->getPort());
-    socket->establishConnection(hostname, req->getPort());
+    socket->establishConnection(resolvedAddresses.front(), req->getPort());
     command = new FtpNegotiationCommand(cuid, req, _requestGroup, e, socket);
   }
-  e->commands.push_back(command);
-  return true;
-}
-
-bool FtpInitiateConnectionCommand::useHttpProxy() const {
-  return e->option->get(PREF_HTTP_PROXY_ENABLED) == V_TRUE;
-}
-
-bool FtpInitiateConnectionCommand::useHttpProxyGet() const {
-  return useHttpProxy() && e->option->get(PREF_FTP_VIA_HTTP_PROXY) == V_GET;
+  return command;
 }
 
-bool FtpInitiateConnectionCommand::useHttpProxyConnect() const {
-  return useHttpProxy() && e->option->get(PREF_FTP_VIA_HTTP_PROXY) == V_TUNNEL;
+bool FtpInitiateConnectionCommand::useHTTPProxyGet() const {
+  return useHTTPProxy() && e->option->get(PREF_FTP_VIA_HTTP_PROXY) == V_GET;
 }
 
-#ifdef ENABLE_ASYNC_DNS
-bool FtpInitiateConnectionCommand::nameResolveFinished() const {
-  return nameResolver->getStatus() ==  NameResolver::STATUS_SUCCESS ||
-    nameResolver->getStatus() == NameResolver::STATUS_ERROR;
+bool FtpInitiateConnectionCommand::useHTTPProxyConnect() const {
+  return useHTTPProxy() && e->option->get(PREF_FTP_VIA_HTTP_PROXY) == V_TUNNEL;
 }
-#endif // ENABLE_ASYNC_DNS
 
 } // namespace aria2

+ 6 - 10
src/FtpInitiateConnectionCommand.h

@@ -35,21 +35,17 @@
 #ifndef _D_FTP_INITIATE_CONNECTION_COMMAND_H_
 #define _D_FTP_INITIATE_CONNECTION_COMMAND_H_
 
-#include "AbstractCommand.h"
+#include "InitiateConnectionCommand.h"
 
 namespace aria2 {
 
-class FtpInitiateConnectionCommand : public AbstractCommand {
+class FtpInitiateConnectionCommand : public InitiateConnectionCommand {
 private:
-  SharedHandle<NameResolver> nameResolver;
-  bool useHttpProxy() const;
-  bool useHttpProxyGet() const;
-  bool useHttpProxyConnect() const;
-#ifdef ENABLE_ASYNC_DNS
-  virtual bool nameResolveFinished() const;
-#endif // ENABLE_ASYNC_DNS
+  bool useHTTPProxyGet() const;
+  bool useHTTPProxyConnect() const;
 protected:
-  virtual bool executeInternal();
+  virtual Command* createNextCommand
+  (const std::deque<std::string>& resolvedAddresses);
 public:
   FtpInitiateConnectionCommand(int cuid, const SharedHandle<Request>& req,
 			       RequestGroup* requestGroup, DownloadEngine* e);

+ 7 - 0
src/HelpItemFactory.cc

@@ -458,6 +458,13 @@ TagContainerHandle HelpItemFactory::createHelpItems(const Option* op)
     item->addTag(TAG_ADVANCED);
     tc->addItem(item);
   }
+#ifdef ENABLE_ASYNC_DNS
+  {
+    HelpItemHandle item(new HelpItem(PREF_ASYNC_DNS, TEXT_ASYNC_DNS, op->get(PREF_ASYNC_DNS)));
+    item->addTag(TAG_ADVANCED);
+    tc->addItem(item);
+  }
+#endif // ENABLE_ASYNC_DNS
   {
     HelpItemHandle item(new HelpItem("help", TEXT_HELP, TAG_BASIC));
     item->setAvailableValues

+ 19 - 54
src/HttpInitiateConnectionCommand.cc

@@ -33,7 +33,6 @@
  */
 /* copyright --> */
 #include "HttpInitiateConnectionCommand.h"
-#include "NameResolver.h"
 #include "Request.h"
 #include "DownloadEngine.h"
 #include "HttpConnection.h"
@@ -43,7 +42,6 @@
 #include "HttpProxyRequestCommand.h"
 #include "DlAbortEx.h"
 #include "Option.h"
-#include "Util.h"
 #include "Logger.h"
 #include "Socket.h"
 #include "message.h"
@@ -51,46 +49,24 @@
 
 namespace aria2 {
 
-HttpInitiateConnectionCommand::HttpInitiateConnectionCommand(int cuid,
-							     const RequestHandle& req,
-							     RequestGroup* requestGroup,
-							     DownloadEngine* e):
-  AbstractCommand(cuid, req, requestGroup, e),
-  nameResolver(new NameResolver())
-{
-  setTimeout(e->option->getAsInt(PREF_DNS_TIMEOUT));
-  setStatus(Command::STATUS_ONESHOT_REALTIME);
-  disableReadCheckSocket();
-  disableWriteCheckSocket();
-}
+HttpInitiateConnectionCommand::HttpInitiateConnectionCommand
+(int cuid,
+ const RequestHandle& req,
+ RequestGroup* requestGroup,
+ DownloadEngine* e):
+  InitiateConnectionCommand(cuid, req, requestGroup, e) {}
 
-HttpInitiateConnectionCommand::~HttpInitiateConnectionCommand() {
-#ifdef ENABLE_ASYNC_DNS
-  disableNameResolverCheck(nameResolver);
-#endif // ENABLE_ASYNC_DNS
-}
+HttpInitiateConnectionCommand::~HttpInitiateConnectionCommand() {}
 
-bool HttpInitiateConnectionCommand::executeInternal() {
-  std::string hostname;
-  if(useProxy()) {
-    hostname = e->option->get(PREF_HTTP_PROXY_HOST);
-  } else {
-    hostname = req->getHost();
-  }
-  if(!Util::isNumbersAndDotsNotation(hostname)) {
-    if(resolveHostname(hostname, nameResolver)) {
-      hostname = nameResolver->getAddrString();
-    } else {
-      e->commands.push_back(this);
-      return false;
-    }
-  }
+Command* HttpInitiateConnectionCommand::createNextCommand
+(const std::deque<std::string>& resolvedAddresses)
+{
   Command* command;
-  if(useProxy()) {
+  if(useHTTPProxy()) {
     logger->info(MSG_CONNECTING_TO_SERVER, cuid,
 		 e->option->get(PREF_HTTP_PROXY_HOST).c_str(),
 		 e->option->getAsInt(PREF_HTTP_PROXY_PORT));
-    socket->establishConnection(hostname,
+    socket->establishConnection(resolvedAddresses.front(),
 				e->option->getAsInt(PREF_HTTP_PROXY_PORT));
     if(useProxyTunnel()) {
       command = new HttpProxyRequestCommand(cuid, req, _requestGroup, e, socket);
@@ -104,12 +80,11 @@ bool HttpInitiateConnectionCommand::executeInternal() {
     }
   } else {
     SharedHandle<SocketCore> pooledSocket =
-      e->popPooledSocket(hostname, req->getPort());
-
+      e->popPooledSocket(resolvedAddresses, req->getPort());
     if(pooledSocket.isNull()) {
       logger->info(MSG_CONNECTING_TO_SERVER, cuid, req->getHost().c_str(),
 		   req->getPort());
-      socket->establishConnection(hostname, req->getPort());
+      socket->establishConnection(resolvedAddresses.front(), req->getPort());
     } else {
       socket = pooledSocket;
     }
@@ -117,27 +92,17 @@ bool HttpInitiateConnectionCommand::executeInternal() {
     command = new HttpRequestCommand(cuid, req, _requestGroup, httpConnection,
 				     e, socket);
   }
-  e->commands.push_back(command);
-  return true;
-}
-
-bool HttpInitiateConnectionCommand::useProxy() {
-  return e->option->get(PREF_HTTP_PROXY_ENABLED) == V_TRUE;
+  return command;
 }
 
-bool HttpInitiateConnectionCommand::useProxyGet() {
+bool HttpInitiateConnectionCommand::useProxyGet() const
+{
   return e->option->get(PREF_HTTP_PROXY_METHOD) == V_GET;
 }
 
-bool HttpInitiateConnectionCommand::useProxyTunnel() {
+bool HttpInitiateConnectionCommand::useProxyTunnel() const
+{
   return e->option->get(PREF_HTTP_PROXY_METHOD) == V_TUNNEL;
 }
 
-#ifdef ENABLE_ASYNC_DNS
-bool HttpInitiateConnectionCommand::nameResolveFinished() const {
-  return nameResolver->getStatus() ==  NameResolver::STATUS_SUCCESS ||
-    nameResolver->getStatus() == NameResolver::STATUS_ERROR;
-}
-#endif // ENABLE_ASYNC_DNS
-
 } // namespace aria2

+ 6 - 18
src/HttpInitiateConnectionCommand.h

@@ -35,29 +35,17 @@
 #ifndef _D_HTTP_INITIATE_CONNECTION_COMMAND_H_
 #define _D_HTTP_INITIATE_CONNECTION_COMMAND_H_
 
-#include "AbstractCommand.h"
+#include "InitiateConnectionCommand.h"
 
 namespace aria2 {
 
-class HttpInitiateConnectionCommand : public AbstractCommand {
+class HttpInitiateConnectionCommand : public InitiateConnectionCommand {
 private:
-  SharedHandle<NameResolver> nameResolver;
-  bool useProxy();
-  bool useProxyGet();
-  bool useProxyTunnel();
+  bool useProxyGet() const;
+  bool useProxyTunnel() const;
 protected:
-  /**
-   * Connect to the server.
-   * This method just send connection request to the server.
-   * Using nonblocking mode of socket, this funtion returns immediately
-   * after send connection packet to the server.
-   * Whether or not the connection is established successfully is
-   * evaluated by RequestCommand.
-   */
-  virtual bool executeInternal();
-#ifdef ENABLE_ASYNC_DNS
-  virtual bool nameResolveFinished() const;
-#endif // ENABLE_ASYNC_DNS
+  virtual Command* createNextCommand
+  (const std::deque<std::string>& resolvedAddresses);
 public:
   HttpInitiateConnectionCommand(int cuid, const SharedHandle<Request>& req,
 				RequestGroup* requestGroup,

+ 109 - 0
src/InitiateConnectionCommand.cc

@@ -0,0 +1,109 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 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 "InitiateConnectionCommand.h"
+#include "Request.h"
+#include "DownloadEngine.h"
+#include "Option.h"
+#include "Logger.h"
+#include "message.h"
+#include "prefs.h"
+#include "NameResolver.h"
+#include "DNSCache.h"
+
+namespace aria2 {
+
+InitiateConnectionCommand::InitiateConnectionCommand
+(int cuid,
+ const RequestHandle& req,
+ RequestGroup* requestGroup,
+ DownloadEngine* e):
+  AbstractCommand(cuid, req, requestGroup, e)
+{
+  setTimeout(e->option->getAsInt(PREF_DNS_TIMEOUT));
+  setStatus(Command::STATUS_ONESHOT_REALTIME);
+  disableReadCheckSocket();
+  disableWriteCheckSocket();
+}
+
+InitiateConnectionCommand::~InitiateConnectionCommand() {}
+
+bool InitiateConnectionCommand::executeInternal() {
+  std::string hostname;
+  if(useHTTPProxy()) {
+    hostname = e->option->get(PREF_HTTP_PROXY_HOST);
+  } else {
+    hostname = req->getHost();
+  }
+  std::deque<std::string> addrs;
+  std::string ipaddr = DNSCacheSingletonHolder::instance()->find(hostname);
+  if(ipaddr.empty()) {
+#ifdef ENABLE_ASYNC_DNS
+    if(e->option->getAsBool(PREF_ASYNC_DNS)) {
+      if(!isAsyncNameResolverInitialized()) {
+	initAsyncNameResolver(hostname);
+      }
+      if(asyncResolveHostname()) {
+	addrs = getResolvedAddresses();
+      } else {
+	e->commands.push_back(this);
+	return false;
+      }
+    } else
+#endif // ENABLE_ASYNC_DNS
+      {
+	NameResolver res;
+	res.setSocktype(SOCK_STREAM);
+	addrs = res.resolve(hostname);
+      }
+    logger->info(MSG_NAME_RESOLUTION_COMPLETE, cuid,
+		 hostname.c_str(),
+		 addrs.front().c_str());
+    DNSCacheSingletonHolder::instance()->put(hostname, addrs.front());
+  } else {
+    logger->info(MSG_DNS_CACHE_HIT, cuid, hostname.c_str(), ipaddr.c_str());
+    addrs.push_back(ipaddr);
+  }
+
+  Command* command = createNextCommand(addrs);
+  e->commands.push_back(command);
+  return true;
+}
+
+bool InitiateConnectionCommand::useHTTPProxy() const
+{
+  return e->option->get(PREF_HTTP_PROXY_ENABLED) == V_TRUE;
+}
+
+} // namespace aria2

+ 66 - 0
src/InitiateConnectionCommand.h

@@ -0,0 +1,66 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 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 _D_INITIATE_CONNECTION_COMMAND_H_
+#define _D_INITIATE_CONNECTION_COMMAND_H_
+
+#include "AbstractCommand.h"
+
+namespace aria2 {
+
+class InitiateConnectionCommand : public AbstractCommand {
+protected:
+  bool useHTTPProxy() const;
+
+  /**
+   * Connect to the server.
+   * This method just send connection request to the server.
+   * Using nonblocking mode of socket, this funtion returns immediately
+   * after send connection packet to the server.
+   */
+  virtual bool executeInternal();
+
+  virtual Command* createNextCommand
+  (const std::deque<std::string>& resolvedAddresses) = 0;
+public:
+  InitiateConnectionCommand(int cuid, const SharedHandle<Request>& req,
+			    RequestGroup* requestGroup,
+			    DownloadEngine* e);
+
+  virtual ~InitiateConnectionCommand();
+};
+
+} // namespace aria2
+
+#endif // _D_INITIATE_CONNECTION_COMMAND_H_

+ 6 - 1
src/Makefile.am

@@ -184,7 +184,12 @@ SRCS =  Socket.h\
 	ProtocolDetector.cc ProtocolDetector.h\
 	NullStatCalc.h\
 	StringFormat.cc StringFormat.h\
-	HttpNullDownloadCommand.cc HttpNullDownloadCommand.h
+	HttpNullDownloadCommand.cc HttpNullDownloadCommand.h\
+	InitiateConnectionCommand.cc InitiateConnectionCommand.h
+
+if ENABLE_ASYNC_DNS
+SRCS += AsyncNameResolver.cc AsyncNameResolver.h
+endif # ENABLE_ASYNC_DNS
 
 if ENABLE_MESSAGE_DIGEST
 SRCS += IteratableChunkChecksumValidator.cc IteratableChunkChecksumValidator.h\

+ 42 - 34
src/Makefile.in

@@ -39,7 +39,8 @@ build_triplet = @build@
 host_triplet = @host@
 target_triplet = @target@
 bin_PROGRAMS = aria2c$(EXEEXT)
-@ENABLE_MESSAGE_DIGEST_TRUE@am__append_1 = IteratableChunkChecksumValidator.cc IteratableChunkChecksumValidator.h\
+@ENABLE_ASYNC_DNS_TRUE@am__append_1 = AsyncNameResolver.cc AsyncNameResolver.h
+@ENABLE_MESSAGE_DIGEST_TRUE@am__append_2 = IteratableChunkChecksumValidator.cc IteratableChunkChecksumValidator.h\
 @ENABLE_MESSAGE_DIGEST_TRUE@	IteratableChecksumValidator.cc IteratableChecksumValidator.h\
 @ENABLE_MESSAGE_DIGEST_TRUE@	CheckIntegrityCommand.cc CheckIntegrityCommand.h\
 @ENABLE_MESSAGE_DIGEST_TRUE@	ChecksumCheckIntegrityEntry.cc ChecksumCheckIntegrityEntry.h\
@@ -48,7 +49,7 @@ bin_PROGRAMS = aria2c$(EXEEXT)
 @ENABLE_MESSAGE_DIGEST_TRUE@	Checksum.h\
 @ENABLE_MESSAGE_DIGEST_TRUE@	ChunkChecksum.h
 
-@ENABLE_BITTORRENT_TRUE@am__append_2 = MetaEntry.h\
+@ENABLE_BITTORRENT_TRUE@am__append_3 = MetaEntry.h\
 @ENABLE_BITTORRENT_TRUE@	Data.cc Data.h\
 @ENABLE_BITTORRENT_TRUE@	Dictionary.cc Dictionary.h\
 @ENABLE_BITTORRENT_TRUE@	List.cc List.h\
@@ -225,7 +226,7 @@ bin_PROGRAMS = aria2c$(EXEEXT)
 @ENABLE_BITTORRENT_TRUE@	BtLeecherStateChoke.cc BtLeecherStateChoke.h\
 @ENABLE_BITTORRENT_TRUE@	BtSeederStateChoke.cc BtSeederStateChoke.h
 
-@ENABLE_METALINK_TRUE@am__append_3 = Metalinker.cc Metalinker.h\
+@ENABLE_METALINK_TRUE@am__append_4 = Metalinker.cc Metalinker.h\
 @ENABLE_METALINK_TRUE@	MetalinkEntry.cc MetalinkEntry.h\
 @ENABLE_METALINK_TRUE@	MetalinkResource.cc MetalinkResource.h\
 @ENABLE_METALINK_TRUE@	MetalinkProcessor.h\
@@ -253,17 +254,17 @@ bin_PROGRAMS = aria2c$(EXEEXT)
 @ENABLE_METALINK_TRUE@	MetalinkPostDownloadHandler.cc MetalinkPostDownloadHandler.h\
 @ENABLE_METALINK_TRUE@	MetalinkHelper.cc MetalinkHelper.h
 
-@ENABLE_LIBXML2_TRUE@am__append_4 = XML2SAXMetalinkProcessor.cc XML2SAXMetalinkProcessor.h
-@ENABLE_LIBEXPAT_TRUE@am__append_5 = ExpatMetalinkProcessor.cc ExpatMetalinkProcessor.h
-@HAVE_BASENAME_FALSE@am__append_6 = libgen.c libgen.h
-@HAVE_GETADDRINFO_FALSE@am__append_7 = getaddrinfo.c getaddrinfo.h
-@HAVE_GAI_STRERROR_FALSE@am__append_8 = gai_strerror.c gai_strerror.h
-@HAVE_GETTIMEOFDAY_FALSE@am__append_9 = gettimeofday.c gettimeofday.h \
+@ENABLE_LIBXML2_TRUE@am__append_5 = XML2SAXMetalinkProcessor.cc XML2SAXMetalinkProcessor.h
+@ENABLE_LIBEXPAT_TRUE@am__append_6 = ExpatMetalinkProcessor.cc ExpatMetalinkProcessor.h
+@HAVE_BASENAME_FALSE@am__append_7 = libgen.c libgen.h
+@HAVE_GETADDRINFO_FALSE@am__append_8 = getaddrinfo.c getaddrinfo.h
+@HAVE_GAI_STRERROR_FALSE@am__append_9 = gai_strerror.c gai_strerror.h
+@HAVE_GETTIMEOFDAY_FALSE@am__append_10 = gettimeofday.c gettimeofday.h \
 @HAVE_GETTIMEOFDAY_FALSE@	gettimeofday.c gettimeofday.h
-@HAVE_INET_ATON_FALSE@am__append_10 = inet_aton.c inet_aton.h
-@HAVE_LOCALTIME_R_FALSE@am__append_11 = localtime_r.c localtime_r.h
-@HAVE_STRPTIME_FALSE@am__append_12 = strptime.c strptime.h
-@HAVE_TIMEGM_FALSE@am__append_13 = timegm.c timegm.h
+@HAVE_INET_ATON_FALSE@am__append_11 = inet_aton.c inet_aton.h
+@HAVE_LOCALTIME_R_FALSE@am__append_12 = localtime_r.c localtime_r.h
+@HAVE_STRPTIME_FALSE@am__append_13 = strptime.c strptime.h
+@HAVE_TIMEGM_FALSE@am__append_14 = timegm.c timegm.h
 subdir = src
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in alloca.c
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -406,6 +407,8 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 	usage_text.h ProtocolDetector.cc ProtocolDetector.h \
 	NullStatCalc.h StringFormat.cc StringFormat.h \
 	HttpNullDownloadCommand.cc HttpNullDownloadCommand.h \
+	InitiateConnectionCommand.cc InitiateConnectionCommand.h \
+	AsyncNameResolver.cc AsyncNameResolver.h \
 	IteratableChunkChecksumValidator.cc \
 	IteratableChunkChecksumValidator.h \
 	IteratableChecksumValidator.cc IteratableChecksumValidator.h \
@@ -560,13 +563,14 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 	getaddrinfo.h gai_strerror.c gai_strerror.h gettimeofday.c \
 	gettimeofday.h inet_aton.c inet_aton.h localtime_r.c \
 	localtime_r.h strptime.c strptime.h timegm.c timegm.h
-@ENABLE_MESSAGE_DIGEST_TRUE@am__objects_1 = IteratableChunkChecksumValidator.$(OBJEXT) \
+@ENABLE_ASYNC_DNS_TRUE@am__objects_1 = AsyncNameResolver.$(OBJEXT)
+@ENABLE_MESSAGE_DIGEST_TRUE@am__objects_2 = IteratableChunkChecksumValidator.$(OBJEXT) \
 @ENABLE_MESSAGE_DIGEST_TRUE@	IteratableChecksumValidator.$(OBJEXT) \
 @ENABLE_MESSAGE_DIGEST_TRUE@	CheckIntegrityCommand.$(OBJEXT) \
 @ENABLE_MESSAGE_DIGEST_TRUE@	ChecksumCheckIntegrityEntry.$(OBJEXT) \
 @ENABLE_MESSAGE_DIGEST_TRUE@	messageDigest.$(OBJEXT) \
 @ENABLE_MESSAGE_DIGEST_TRUE@	MessageDigestHelper.$(OBJEXT)
-@ENABLE_BITTORRENT_TRUE@am__objects_2 = Data.$(OBJEXT) \
+@ENABLE_BITTORRENT_TRUE@am__objects_3 = Data.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	Dictionary.$(OBJEXT) List.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	MetaFileUtil.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	BencodeVisitor.$(OBJEXT) \
@@ -677,7 +681,7 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 @ENABLE_BITTORRENT_TRUE@	MSEHandshake.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	BtLeecherStateChoke.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	BtSeederStateChoke.$(OBJEXT)
-@ENABLE_METALINK_TRUE@am__objects_3 = Metalinker.$(OBJEXT) \
+@ENABLE_METALINK_TRUE@am__objects_4 = Metalinker.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	MetalinkEntry.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	MetalinkResource.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	MetalinkProcessorFactory.$(OBJEXT) \
@@ -702,20 +706,20 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 @ENABLE_METALINK_TRUE@	Metalink2RequestGroup.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	MetalinkPostDownloadHandler.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	MetalinkHelper.$(OBJEXT)
-@ENABLE_LIBXML2_TRUE@am__objects_4 =  \
+@ENABLE_LIBXML2_TRUE@am__objects_5 =  \
 @ENABLE_LIBXML2_TRUE@	XML2SAXMetalinkProcessor.$(OBJEXT)
-@ENABLE_LIBEXPAT_TRUE@am__objects_5 =  \
+@ENABLE_LIBEXPAT_TRUE@am__objects_6 =  \
 @ENABLE_LIBEXPAT_TRUE@	ExpatMetalinkProcessor.$(OBJEXT)
-@HAVE_BASENAME_FALSE@am__objects_6 = libgen.$(OBJEXT)
-@HAVE_GETADDRINFO_FALSE@am__objects_7 = getaddrinfo.$(OBJEXT)
-@HAVE_GAI_STRERROR_FALSE@am__objects_8 = gai_strerror.$(OBJEXT)
-@HAVE_GETTIMEOFDAY_FALSE@am__objects_9 = gettimeofday.$(OBJEXT) \
+@HAVE_BASENAME_FALSE@am__objects_7 = libgen.$(OBJEXT)
+@HAVE_GETADDRINFO_FALSE@am__objects_8 = getaddrinfo.$(OBJEXT)
+@HAVE_GAI_STRERROR_FALSE@am__objects_9 = gai_strerror.$(OBJEXT)
+@HAVE_GETTIMEOFDAY_FALSE@am__objects_10 = gettimeofday.$(OBJEXT) \
 @HAVE_GETTIMEOFDAY_FALSE@	gettimeofday.$(OBJEXT)
-@HAVE_INET_ATON_FALSE@am__objects_10 = inet_aton.$(OBJEXT)
-@HAVE_LOCALTIME_R_FALSE@am__objects_11 = localtime_r.$(OBJEXT)
-@HAVE_STRPTIME_FALSE@am__objects_12 = strptime.$(OBJEXT)
-@HAVE_TIMEGM_FALSE@am__objects_13 = timegm.$(OBJEXT)
-am__objects_14 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
+@HAVE_INET_ATON_FALSE@am__objects_11 = inet_aton.$(OBJEXT)
+@HAVE_LOCALTIME_R_FALSE@am__objects_12 = localtime_r.$(OBJEXT)
+@HAVE_STRPTIME_FALSE@am__objects_13 = strptime.$(OBJEXT)
+@HAVE_TIMEGM_FALSE@am__objects_14 = timegm.$(OBJEXT)
+am__objects_15 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
 	AbstractCommand.$(OBJEXT) \
 	InitiateConnectionCommandFactory.$(OBJEXT) \
 	DownloadCommand.$(OBJEXT) \
@@ -783,12 +787,13 @@ am__objects_14 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
 	HelpItemFactory.$(OBJEXT) SingleFileDownloadContext.$(OBJEXT) \
 	TimedHaltCommand.$(OBJEXT) ProtocolDetector.$(OBJEXT) \
 	StringFormat.$(OBJEXT) HttpNullDownloadCommand.$(OBJEXT) \
-	$(am__objects_1) $(am__objects_2) $(am__objects_3) \
-	$(am__objects_4) $(am__objects_5) $(am__objects_6) \
-	$(am__objects_7) $(am__objects_8) $(am__objects_9) \
-	$(am__objects_10) $(am__objects_11) $(am__objects_12) \
-	$(am__objects_13)
-am_libaria2c_a_OBJECTS = $(am__objects_14)
+	InitiateConnectionCommand.$(OBJEXT) $(am__objects_1) \
+	$(am__objects_2) $(am__objects_3) $(am__objects_4) \
+	$(am__objects_5) $(am__objects_6) $(am__objects_7) \
+	$(am__objects_8) $(am__objects_9) $(am__objects_10) \
+	$(am__objects_11) $(am__objects_12) $(am__objects_13) \
+	$(am__objects_14)
+am_libaria2c_a_OBJECTS = $(am__objects_15)
 libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS)
 am__installdirs = "$(DESTDIR)$(bindir)"
 binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
@@ -1124,11 +1129,12 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \
 	usage_text.h ProtocolDetector.cc ProtocolDetector.h \
 	NullStatCalc.h StringFormat.cc StringFormat.h \
 	HttpNullDownloadCommand.cc HttpNullDownloadCommand.h \
+	InitiateConnectionCommand.cc InitiateConnectionCommand.h \
 	$(am__append_1) $(am__append_2) $(am__append_3) \
 	$(am__append_4) $(am__append_5) $(am__append_6) \
 	$(am__append_7) $(am__append_8) $(am__append_9) \
 	$(am__append_10) $(am__append_11) $(am__append_12) \
-	$(am__append_13)
+	$(am__append_13) $(am__append_14)
 noinst_LIBRARIES = libaria2c.a
 libaria2c_a_SOURCES = $(SRCS)
 aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\
@@ -1225,6 +1231,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AbstractSingleDiskAdaptor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ActivePeerConnectionCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AnnounceList.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AsyncNameResolver.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AuthConfig.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AuthConfigFactory.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AutoSaveCommand.Po@am__quote@
@@ -1390,6 +1397,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpResponse.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpResponseCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InitialMetalinkParserState.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InitiateConnectionCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InitiateConnectionCommandFactory.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InitiatorMSEHandshakeCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IteratableChecksumValidator.Po@am__quote@

+ 23 - 78
src/NameResolver.cc

@@ -36,98 +36,43 @@
 #include "DlAbortEx.h"
 #include "message.h"
 #include "StringFormat.h"
+#include "Util.h"
 #include <cstring>
 
 namespace aria2 {
 
-#ifdef ENABLE_ASYNC_DNS
+NameResolver::NameResolver():_socktype(0) {}
 
-#ifdef HAVE_LIBCARES1_5
-void callback(void* arg, int status, int timeouts, struct hostent* host)
-#else
-void callback(void* arg, int status, struct hostent* host)
-#endif // HAVE_LIBCARES1_5
+std::deque<std::string> NameResolver::resolve(const std::string& hostname)
 {
-  NameResolver* resolverPtr = (NameResolver*)arg;
-#ifdef HAVE_LIBARES
-  // This block is required since the assertion in ares_strerror fails
-  // if status = ARES_EDESTRUCTION is passed to ares_strerror as 1st argument.
-  // This does not happen in c-ares.
-  if(status == ARES_EDESTRUCTION) {
-    // we simply return in this case.
-    return;
-  }
-#endif
-  if(status != ARES_SUCCESS) {
-#ifdef HAVE_LIBCARES
-    resolverPtr->error = ares_strerror(status);
-#else
-    resolverPtr->error = ares_strerror(status, 0);
-#endif // HAVE_LIBCARES
-    resolverPtr->status = NameResolver::STATUS_ERROR;
-    return;
-  }
-  memcpy(&resolverPtr->addr, *host->h_addr_list, sizeof(struct in_addr));
-  resolverPtr->status = NameResolver::STATUS_SUCCESS;
-}
-
-void NameResolver::resolve(const std::string& name)
-{
-  status = STATUS_QUERYING;
-  ares_gethostbyname(channel, name.c_str(), AF_INET, callback, this);
-}
-
-std::string NameResolver::getAddrString() const
-{
-  return inet_ntoa(addr);
-}
-
-void NameResolver::setAddr(const std::string& addrString)
-{
-  inet_aton(addrString.c_str(), &addr);
-}
- 
-void NameResolver::reset()
-{
-  status = STATUS_READY;
-  ares_destroy(channel);
-  // TODO evaluate return value
-  ares_init(&channel);
-}
-
-#else // ENABLE_ASYNC_DNS
-
-void NameResolver::resolve(const std::string& hostname)
-{
-  memset(&_addr, 0, sizeof(in_addr));
-  struct addrinfo ai;
-  memset((char*)&ai, 0, sizeof(ai));
-  ai.ai_flags = 0;
-  ai.ai_family = PF_INET;
-  ai.ai_socktype = SOCK_STREAM;
-  ai.ai_protocol = 0; 
+  struct addrinfo hints;
   struct addrinfo* res;
-  int ec;
-  if((ec = getaddrinfo(hostname.c_str(), 0, &ai, &res)) != 0) {
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = AF_UNSPEC;
+  hints.ai_socktype = _socktype;
+  hints.ai_flags = 0;
+  hints.ai_protocol = 0;
+  int s;
+  s = getaddrinfo(hostname.c_str(), "0", &hints, &res);
+  if(s) {
     throw DlAbortEx(StringFormat(EX_RESOLVE_HOSTNAME,
-				 hostname.c_str(), gai_strerror(ec)).str());
+				 hostname.c_str(), gai_strerror(s)).str());
+  }
+  std::deque<std::string> addrs;
+  struct addrinfo* rp;
+  for(rp = res; rp; rp = rp->ai_next) {
+    std::pair<std::string, uint16_t> addressPort
+      = Util::getNumericNameInfo(rp->ai_addr, rp->ai_addrlen);
+    addrs.push_back(addressPort.first);
   }
-  _addr = ((struct sockaddr_in*)res->ai_addr)->sin_addr;
   freeaddrinfo(res);
-}
 
-std::string NameResolver::getAddrString() const
-{
-  return inet_ntoa(_addr);
+  return addrs;
 }
 
-void NameResolver::setAddr(const std::string& addrString)
+void NameResolver::setSocktype(int socktype)
 {
-  inet_aton(addrString.c_str(), &_addr);
+  _socktype = socktype;
 }
 
-void NameResolver::reset() {}
-
-#endif // ENABLE_ASYNC_DNS
-
 } // namespace aria2

+ 6 - 98
src/NameResolver.h

@@ -36,115 +36,23 @@
 #define _D_NAME_RESOLVER_H_
 
 #include "common.h"
-#include "SharedHandle.h"
-#include "a2netcompat.h"
 #include <string>
-
-#ifdef ENABLE_ASYNC_DNS
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-#include <ares.h>
-#ifdef __cplusplus
-} /* end of extern "C" */
-#endif
-
-#endif // ENABLE_ASYNC_DNS
+#include <deque>
 
 namespace aria2 {
 
-#ifdef ENABLE_ASYNC_DNS
-
-#ifdef HAVE_LIBCARES1_5
-void callback(void* arg, int status, int timeouts, struct hostent* host);
-#else
-void callback(void* arg, int status, struct hostent* host);
-#endif // HAVE_LIBCARES1_5
-
-class NameResolver {
-#ifdef HAVE_LIBCARES1_5
-  friend void callback(void* arg, int status, int timeouts, struct hostent* host);
-#else
-  friend void callback(void* arg, int status, struct hostent* host);
-#endif // HAVE_LIBCARES1_5
-
-public:
-  enum STATUS {
-    STATUS_READY,
-    STATUS_QUERYING,
-    STATUS_SUCCESS,
-    STATUS_ERROR,
-  };
-private:
-  STATUS status;
-  ares_channel channel;
-  struct in_addr addr;
-  std::string error;
-public:
-  NameResolver():
-    status(STATUS_READY)
-  {
-    // TODO evaluate return value
-    ares_init(&channel);
-  }
-
-  ~NameResolver() {
-    ares_destroy(channel);
-  }
-
-  void resolve(const std::string& name);
-
-  std::string getAddrString() const;
-
-  const struct in_addr& getAddr() const {
-    return addr;
-  }
-
-  const std::string& getError() const {
-    return error;
-  }
-
-  STATUS getStatus() const {
-    return status;
-  }
-
-  int getFds(fd_set* rfdsPtr, fd_set* wfdsPtr) const {
-    return ares_fds(channel, rfdsPtr, wfdsPtr);
-  }
-
-  void process(fd_set* rfdsPtr, fd_set* wfdsPtr) {
-    ares_process(channel, rfdsPtr, wfdsPtr);
-  }
-
-  bool operator==(const NameResolver& resolver) {
-    return this == &resolver;
-  }
-
-  void setAddr(const std::string& addrString);
-
-  void reset();
-};
-
-#else // ENABLE_ASYNC_DNS
-
 class NameResolver {
 private:
-  struct in_addr _addr;
+  int _socktype;
 public:
-  void resolve(const std::string& hostname);
+  NameResolver();
 
-  std::string getAddrString() const;
-  
-  void setAddr(const std::string& addrString);
+  std::deque<std::string> resolve(const std::string& hostname);
 
-  void reset();
+  // specify SOCK_STREAM or SOCK_DGRAM
+  void setSocktype(int socktype);
 };
 
-#endif // ENABLE_ASYNC_DNS
-
-typedef SharedHandle<NameResolver> NameResolverHandle;
-
 } // namespace aria2
 
 #endif // _D_NAME_RESOLVER_H_

+ 3 - 0
src/OptionHandlerFactory.cc

@@ -128,6 +128,9 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
   handlers.push_back(SH(new BooleanOptionHandler(PREF_BT_REQUIRE_CRYPTO)));
   handlers.push_back(SH(new CumulativeOptionHandler(PREF_HEADER, "\n")));
   handlers.push_back(SH(new BooleanOptionHandler(PREF_QUIET)));
+#ifdef ENABLE_ASYNC_DNS
+  handlers.push_back(SH(new BooleanOptionHandler(PREF_ASYNC_DNS)));
+#endif // ENABLE_ASYNC_DNS
   return handlers;
 }
 

+ 4 - 17
src/SocketCore.cc

@@ -38,6 +38,7 @@
 #include "DlRetryEx.h"
 #include "DlAbortEx.h"
 #include "StringFormat.h"
+#include "Util.h"
 #include <unistd.h>
 #include <cerrno>
 #include <cstring>
@@ -169,20 +170,6 @@ SocketCore* SocketCore::acceptConnection() const
   return new SocketCore(fd, _sockType);
 }
 
-std::pair<std::string, uint16_t>
-SocketCore::getNameInfoInNumeric(const struct sockaddr* sockaddr, socklen_t len)
-{
-  char host[NI_MAXHOST];
-  char service[NI_MAXSERV];
-  int s = getnameinfo(sockaddr, len, host, NI_MAXHOST, service, NI_MAXSERV,
-		      NI_NUMERICHOST|NI_NUMERICSERV);
-  if(s != 0) {
-    throw DlAbortEx(StringFormat("Failed to get hostname and port. cause: %s",
-				 gai_strerror(s)).str());
-  }
-  return std::pair<std::string, uint16_t>(host, atoi(service)); // TODO
-}
-
 void SocketCore::getAddrInfo(std::pair<std::string, uint16_t>& addrinfo) const
 {
   struct sockaddr_storage sockaddr;
@@ -191,7 +178,7 @@ void SocketCore::getAddrInfo(std::pair<std::string, uint16_t>& addrinfo) const
   if(getsockname(sockfd, addrp, &len) == -1) {
     throw DlAbortEx(StringFormat(EX_SOCKET_GET_NAME, errorMsg()).str());
   }
-  addrinfo = SocketCore::getNameInfoInNumeric(addrp, len);
+  addrinfo = Util::getNumericNameInfo(addrp, len);
 }
 
 void SocketCore::getPeerInfo(std::pair<std::string, uint16_t>& peerinfo) const
@@ -202,7 +189,7 @@ void SocketCore::getPeerInfo(std::pair<std::string, uint16_t>& peerinfo) const
   if(getpeername(sockfd, addrp, &len) == -1) {
     throw DlAbortEx(StringFormat(EX_SOCKET_GET_NAME, errorMsg()).str());
   }
-  peerinfo = SocketCore::getNameInfoInNumeric(addrp, len);
+  peerinfo = Util::getNumericNameInfo(addrp, len);
 }
 
 void SocketCore::establishConnection(const std::string& host, uint16_t port)
@@ -679,7 +666,7 @@ ssize_t SocketCore::readDataFrom(char* data, size_t len,
   if(r == -1) {
     throw DlAbortEx(StringFormat(EX_SOCKET_RECV, errorMsg()).str());
   }
-  sender = SocketCore::getNameInfoInNumeric(addrp, sockaddrlen);
+  sender = Util::getNumericNameInfo(addrp, sockaddrlen);
 
   return r;
 }

+ 0 - 3
src/SocketCore.h

@@ -87,9 +87,6 @@ private:
   static int error();
   static const char *errorMsg();
   static const char *errorMsg(const int err);
-
-  static std::pair<std::string, uint16_t>
-  getNameInfoInNumeric(const struct sockaddr* sockaddr, socklen_t len);
 public:
   SocketCore(int sockType = SOCK_STREAM);
   ~SocketCore();

+ 14 - 0
src/Util.cc

@@ -858,4 +858,18 @@ void* Util::allocateAlignedMemory(size_t alignment, size_t size)
 }
 #endif // HAVE_POSIX_MEMALIGN
 
+std::pair<std::string, uint16_t>
+Util::getNumericNameInfo(const struct sockaddr* sockaddr, socklen_t len)
+{
+  char host[NI_MAXHOST];
+  char service[NI_MAXSERV];
+  int s = getnameinfo(sockaddr, len, host, NI_MAXHOST, service, NI_MAXSERV,
+		      NI_NUMERICHOST|NI_NUMERICSERV);
+  if(s != 0) {
+    throw DlAbortEx(StringFormat("Failed to get hostname and port. cause: %s",
+				 gai_strerror(s)).str());
+  }
+  return std::pair<std::string, uint16_t>(host, atoi(service)); // TODO
+}
+
 } // namespace aria2

+ 4 - 0
src/Util.h

@@ -39,6 +39,7 @@
 #include "SharedHandle.h"
 #include "IntSequence.h"
 #include "a2time.h"
+#include "a2netcompat.h"
 #include <sys/time.h>
 #include <string>
 #include <utility>
@@ -236,6 +237,9 @@ public:
 #ifdef HAVE_POSIX_MEMALIGN
   static void* allocateAlignedMemory(size_t alignment, size_t size);
 #endif // HAVE_POSIX_MEMALIGN
+
+  static std::pair<std::string, uint16_t>
+  getNumericNameInfo(const struct sockaddr* sockaddr, socklen_t len);
 };
 
 } // namespace aria2

+ 13 - 0
src/option_processing.cc

@@ -144,6 +144,11 @@ Option* createDefaultOption()
   op->put(PREF_BT_REQUIRE_CRYPTO, V_FALSE);
   op->put(PREF_QUIET, V_FALSE);
   op->put(PREF_STOP, "0");
+#ifdef ENABLE_ASYNC_DNS
+  op->put(PREF_ASYNC_DNS, V_TRUE);
+#else
+  op->put(PREF_ASYNC_DNS, V_FALSE);
+#endif // ENABLE_ASYNC_DNS
   return op;
 }
 
@@ -215,6 +220,9 @@ Option* option_processing(int argc, char* const argv[])
       { PREF_STOP, required_argument, &lopt, 214 },
       { PREF_HEADER, required_argument, &lopt, 215 },
       { PREF_QUIET, optional_argument, 0, 'q' },
+#ifdef ENABLE_ASYNC_DNS
+      { PREF_ASYNC_DNS, optional_argument, &lopt, 216 },
+#endif // ENABLE_ASYNC_DNS
 #if defined ENABLE_BITTORRENT || ENABLE_METALINK
       { PREF_SHOW_FILES, no_argument, NULL, 'S' },
       { PREF_SELECT_FILE, required_argument, &lopt, 21 },
@@ -416,6 +424,11 @@ Option* option_processing(int argc, char* const argv[])
       case 215:
 	cmdstream << PREF_HEADER << "=" << optarg << "\n";
 	break;
+#ifdef ENABLE_ASYNC_DNS
+      case 216:
+	cmdstream << PREF_ASYNC_DNS << "=" << toBoolArg(optarg) << "\n";
+	break;
+#endif // ENABLE_ASYNC_DNS
       }
       break;
     }

+ 2 - 0
src/prefs.h

@@ -128,6 +128,8 @@
 #define PREF_STOP "stop"
 // value: true | false
 #define PREF_QUIET "quiet"
+// value: true | false
+#define PREF_ASYNC_DNS "async-dns"
 
 /**
  * FTP related preferences

+ 2 - 0
src/usage_text.h

@@ -336,3 +336,5 @@ _(" --header=HEADER              Append HEADER to HTTP request header. You can u
   "                              http://host/file")
 #define TEXT_QUIET \
 _(" -q, --quiet[=true|false]     Make aria2 quite (no console output).")
+#define TEXT_ASYNC_DNS \
+_(" --async-dns[=true|false]     Enable asynchronous DNS.")