AsyncNameResolverMan.cc 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2013 Tatsuhiro Tsujikawa
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * In addition, as a special exception, the copyright holders give
  22. * permission to link the code of portions of this program with the
  23. * OpenSSL library under certain conditions as described in each
  24. * individual source file, and distribute linked combinations
  25. * including the two.
  26. * You must obey the GNU General Public License in all respects
  27. * for all of the code used other than OpenSSL. If you modify
  28. * file(s) with this exception, you may extend this exception to your
  29. * version of the file(s), but you are not obligated to do so. If you
  30. * do not wish to do so, delete this exception statement from your
  31. * version. If you delete this exception statement from all source
  32. * files in the program, then also delete it here.
  33. */
  34. /* copyright --> */
  35. #include "AsyncNameResolverMan.h"
  36. #include <cassert>
  37. #include "AsyncNameResolver.h"
  38. #include "DownloadEngine.h"
  39. #include "Command.h"
  40. #include "message.h"
  41. #include "fmt.h"
  42. #include "LogFactory.h"
  43. #include "Option.h"
  44. #include "SocketCore.h"
  45. #include "prefs.h"
  46. namespace aria2 {
  47. AsyncNameResolverMan::AsyncNameResolverMan()
  48. : numResolver_(0), resolverCheck_(0), ipv4_(true), ipv6_(true)
  49. {
  50. }
  51. AsyncNameResolverMan::~AsyncNameResolverMan() { assert(!resolverCheck_); }
  52. bool AsyncNameResolverMan::started() const
  53. {
  54. for (size_t i = 0; i < numResolver_; ++i) {
  55. if (asyncNameResolver_[i]) {
  56. return true;
  57. }
  58. }
  59. return false;
  60. }
  61. void AsyncNameResolverMan::startAsync(const std::string& hostname,
  62. DownloadEngine* e, Command* command)
  63. {
  64. numResolver_ = 0;
  65. // Set IPv6 resolver first, so that we can push IPv6 address in
  66. // front of IPv6 address in getResolvedAddress().
  67. if (ipv6_) {
  68. startAsyncFamily(hostname, AF_INET6, e, command);
  69. ++numResolver_;
  70. }
  71. if (ipv4_) {
  72. startAsyncFamily(hostname, AF_INET, e, command);
  73. ++numResolver_;
  74. }
  75. A2_LOG_INFO(
  76. fmt(MSG_RESOLVING_HOSTNAME, command->getCuid(), hostname.c_str()));
  77. }
  78. void AsyncNameResolverMan::startAsyncFamily(const std::string& hostname,
  79. int family, DownloadEngine* e,
  80. Command* command)
  81. {
  82. asyncNameResolver_[numResolver_] =
  83. std::make_shared<AsyncNameResolver>(family
  84. #ifdef HAVE_ARES_ADDR_NODE
  85. ,
  86. e->getAsyncDNSServers()
  87. #endif // HAVE_ARES_ADDR_NODE
  88. );
  89. asyncNameResolver_[numResolver_]->resolve(hostname);
  90. setNameResolverCheck(numResolver_, e, command);
  91. }
  92. void AsyncNameResolverMan::getResolvedAddress(
  93. std::vector<std::string>& res) const
  94. {
  95. for (size_t i = 0; i < numResolver_; ++i) {
  96. if (asyncNameResolver_[i]->getStatus() ==
  97. AsyncNameResolver::STATUS_SUCCESS) {
  98. auto& addrs = asyncNameResolver_[i]->getResolvedAddresses();
  99. res.insert(std::end(res), std::begin(addrs), std::end(addrs));
  100. }
  101. }
  102. return;
  103. }
  104. void AsyncNameResolverMan::setNameResolverCheck(DownloadEngine* e,
  105. Command* command)
  106. {
  107. for (size_t i = 0; i < numResolver_; ++i) {
  108. setNameResolverCheck(i, e, command);
  109. }
  110. }
  111. void AsyncNameResolverMan::setNameResolverCheck(size_t index, DownloadEngine* e,
  112. Command* command)
  113. {
  114. if (asyncNameResolver_[index]) {
  115. assert((resolverCheck_ & (1 << index)) == 0);
  116. resolverCheck_ |= 1 << index;
  117. e->addNameResolverCheck(asyncNameResolver_[index], command);
  118. }
  119. }
  120. void AsyncNameResolverMan::disableNameResolverCheck(DownloadEngine* e,
  121. Command* command)
  122. {
  123. for (size_t i = 0; i < numResolver_; ++i) {
  124. disableNameResolverCheck(i, e, command);
  125. }
  126. }
  127. void AsyncNameResolverMan::disableNameResolverCheck(size_t index,
  128. DownloadEngine* e,
  129. Command* command)
  130. {
  131. if (asyncNameResolver_[index] && (resolverCheck_ & (1 << index))) {
  132. resolverCheck_ &= ~(1 << index);
  133. e->deleteNameResolverCheck(asyncNameResolver_[index], command);
  134. }
  135. }
  136. int AsyncNameResolverMan::getStatus() const
  137. {
  138. size_t success = 0;
  139. size_t error = 0;
  140. bool ipv4Success = false;
  141. for (size_t i = 0; i < numResolver_; ++i) {
  142. switch (asyncNameResolver_[i]->getStatus()) {
  143. case AsyncNameResolver::STATUS_SUCCESS:
  144. ++success;
  145. if (asyncNameResolver_[i]->getFamily() == AF_INET) {
  146. ipv4Success = true;
  147. }
  148. break;
  149. case AsyncNameResolver::STATUS_ERROR:
  150. ++error;
  151. break;
  152. default:
  153. break;
  154. }
  155. }
  156. // If we got a IPv4 lookup response, we don't wait for a IPv6 lookup
  157. // response. This is because DNS servers may drop AAAA queries and we
  158. // have to wait for a long time before timeout. We don't do the
  159. // inverse, because, based on today's deployment of DNS servers,
  160. // almost all of them can respond to A queries just fine.
  161. if ((success && ipv4Success) || success == numResolver_) {
  162. return 1;
  163. }
  164. else if (error == numResolver_) {
  165. return -1;
  166. }
  167. else {
  168. return 0;
  169. }
  170. }
  171. const std::string& AsyncNameResolverMan::getLastError() const
  172. {
  173. for (size_t i = 0; i < numResolver_; ++i) {
  174. if (asyncNameResolver_[i]->getStatus() == AsyncNameResolver::STATUS_ERROR) {
  175. // TODO This is not last error chronologically.
  176. return asyncNameResolver_[i]->getError();
  177. }
  178. }
  179. return A2STR::NIL;
  180. }
  181. void AsyncNameResolverMan::reset(DownloadEngine* e, Command* command)
  182. {
  183. disableNameResolverCheck(e, command);
  184. assert(resolverCheck_ == 0);
  185. for (size_t i = 0; i < numResolver_; ++i) {
  186. asyncNameResolver_[i].reset();
  187. }
  188. numResolver_ = 0;
  189. }
  190. void configureAsyncNameResolverMan(AsyncNameResolverMan* asyncNameResolverMan,
  191. Option* option)
  192. {
  193. // Currently, aria2 checks configured addresses at the startup. But
  194. // there are chances that interfaces are not setup at that
  195. // moment. For example, if aria2 is used as daemon, it may start
  196. // before network interfaces up. To workaround this, we check
  197. // addresses again if both addresses are not configured at the
  198. // startup.
  199. if (!net::getIPv4AddrConfigured() && !net::getIPv6AddrConfigured()) {
  200. net::checkAddrconfig();
  201. }
  202. if (!net::getIPv4AddrConfigured()) {
  203. asyncNameResolverMan->setIPv4(false);
  204. }
  205. if (!net::getIPv6AddrConfigured() || option->getAsBool(PREF_DISABLE_IPV6)) {
  206. asyncNameResolverMan->setIPv6(false);
  207. }
  208. }
  209. } // namespace aria2