diff --git a/configure.ac b/configure.ac index 88778a33..98439946 100644 --- a/configure.ac +++ b/configure.ac @@ -503,18 +503,10 @@ fi have_libcares=no if test "x$with_libcares" = "xyes"; then - PKG_CHECK_MODULES([LIBCARES], [libcares >= 1.7.0], [have_libcares=yes], + PKG_CHECK_MODULES([LIBCARES], [libcares >= 1.16.0], [have_libcares=yes], [have_libcares=no]) if test "x$have_libcares" = "xyes"; then AC_DEFINE([HAVE_LIBCARES], [1], [Define to 1 if you have libcares.]) - save_LIBS=$LIBS - save_CPPFLAGS=$CPPFLAGS - LIBS="$LIBCARES_LIBS $LIBS" - CPPFLAGS="$LIBCARES_CFLAGS $CPPFLAGS" - AC_CHECK_TYPES([ares_addr_node], [], [], [[#include ]]) - AC_CHECK_FUNCS([ares_set_servers]) - LIBS=$save_LIBS - CPPFLAGS=$save_CPPFLAGS # -DCARES_STATICLIB is appended by pkg-config file libcares.pc else diff --git a/src/AsyncNameResolver.cc b/src/AsyncNameResolver.cc index b041d6f9..8d4e2b23 100644 --- a/src/AsyncNameResolver.cc +++ b/src/AsyncNameResolver.cc @@ -40,10 +40,11 @@ #include "LogFactory.h" #include "SocketCore.h" #include "util.h" +#include "EventPoll.h" namespace aria2 { -void callback(void* arg, int status, int timeouts, struct hostent* host) +void callback(void* arg, int status, int timeouts, ares_addrinfo* result) { AsyncNameResolver* resolverPtr = reinterpret_cast(arg); if (status != ARES_SUCCESS) { @@ -51,12 +52,15 @@ void callback(void* arg, int status, int timeouts, struct hostent* host) resolverPtr->status_ = AsyncNameResolver::STATUS_ERROR; return; } - for (char** ap = host->h_addr_list; *ap; ++ap) { + for (auto ap = result->nodes; ap; ap = ap->ai_next) { char addrstring[NI_MAXHOST]; - if (inetNtop(host->h_addrtype, *ap, addrstring, sizeof(addrstring)) == 0) { + auto rv = getnameinfo(ap->ai_addr, ap->ai_addrlen, addrstring, + sizeof(addrstring), nullptr, 0, NI_NUMERICHOST); + if (rv == 0) { resolverPtr->resolvedAddresses_.push_back(addrstring); } } + ares_freeaddrinfo(result); if (resolverPtr->resolvedAddresses_.empty()) { resolverPtr->error_ = "no address returned or address conversion failed"; resolverPtr->status_ = AsyncNameResolver::STATUS_ERROR; @@ -66,24 +70,63 @@ void callback(void* arg, int status, int timeouts, struct hostent* host) } } -AsyncNameResolver::AsyncNameResolver(int family -#ifdef HAVE_ARES_ADDR_NODE - , - ares_addr_node* servers -#endif // HAVE_ARES_ADDR_NODE - ) +namespace { +void sock_state_cb(void* arg, int fd, int read, int write) +{ + auto resolver = static_cast(arg); + + resolver->handle_sock_state(fd, read, write); +} +} // namespace + +void AsyncNameResolver::handle_sock_state(int fd, int read, int write) +{ + int events = 0; + + if (read) { + events |= EventPoll::EVENT_READ; + } + + if (write) { + events |= EventPoll::EVENT_WRITE; + } + + auto it = std::find_if( + std::begin(socks_), std::end(socks_), + [fd](const AsyncNameResolverSocketEntry& ent) { return ent.fd == fd; }); + if (it == std::end(socks_)) { + if (!events) { + return; + } + + socks_.emplace_back(AsyncNameResolverSocketEntry{fd, events}); + + return; + } + + if (!events) { + socks_.erase(it); + return; + } + + (*it).events = events; +} + +AsyncNameResolver::AsyncNameResolver(int family, const std::string& servers) : status_(STATUS_READY), family_(family) { + ares_options opts{}; + opts.sock_state_cb = sock_state_cb; + opts.sock_state_cb_data = this; + // TODO evaluate return value - ares_init(&channel_); -#if defined(HAVE_ARES_SET_SERVERS) && defined(HAVE_ARES_ADDR_NODE) - if (servers) { - // ares_set_servers has been added since c-ares 1.7.1 - if (ares_set_servers(channel_, servers) != ARES_SUCCESS) { - A2_LOG_DEBUG("ares_set_servers failed"); + ares_init_options(&channel_, &opts, ARES_OPT_SOCK_STATE_CB); + + if (!servers.empty()) { + if (ares_set_servers_csv(channel_, servers.c_str()) != ARES_SUCCESS) { + A2_LOG_DEBUG("ares_set_servers_csv failed"); } } -#endif // HAVE_ARES_SET_SERVERS && HAVE_ARES_ADDR_NODE } AsyncNameResolver::~AsyncNameResolver() { ares_destroy(channel_); } @@ -92,25 +135,58 @@ void AsyncNameResolver::resolve(const std::string& name) { hostname_ = name; status_ = STATUS_QUERYING; - ares_gethostbyname(channel_, name.c_str(), family_, callback, this); + + ares_addrinfo_hints hints{}; + hints.ai_family = family_; + + ares_getaddrinfo(channel_, name.c_str(), nullptr, &hints, callback, this); } int AsyncNameResolver::getFds(fd_set* rfdsPtr, fd_set* wfdsPtr) const { - return ares_fds(channel_, rfdsPtr, wfdsPtr); + auto nfds = 0; + + for (const auto& ent : socks_) { + if (ent.events & EventPoll::EVENT_READ) { + FD_SET(ent.fd, rfdsPtr); + nfds = std::max(nfds, ent.fd + 1); + } + + if (ent.events & EventPoll::EVENT_WRITE) { + FD_SET(ent.fd, wfdsPtr); + nfds = std::max(nfds, ent.fd + 1); + } + } + + return nfds; } void AsyncNameResolver::process(fd_set* rfdsPtr, fd_set* wfdsPtr) { - ares_process(channel_, rfdsPtr, wfdsPtr); + for (const auto& ent : socks_) { + ares_socket_t readfd = ARES_SOCKET_BAD; + ares_socket_t writefd = ARES_SOCKET_BAD; + + if (FD_ISSET(ent.fd, rfdsPtr) && (ent.events & EventPoll::EVENT_READ)) { + readfd = ent.fd; + } + + if (FD_ISSET(ent.fd, wfdsPtr) && (ent.events & EventPoll::EVENT_WRITE)) { + writefd = ent.fd; + } + + if (readfd != ARES_SOCKET_BAD || writefd != ARES_SOCKET_BAD) { + process(readfd, writefd); + } + } } #ifdef HAVE_LIBCARES -int AsyncNameResolver::getsock(sock_t* sockets) const +const std::vector& +AsyncNameResolver::getsock() const { - return ares_getsock(channel_, reinterpret_cast(sockets), - ARES_GETSOCK_MAXNUM); + return socks_; } void AsyncNameResolver::process(ares_socket_t readfd, ares_socket_t writefd) @@ -125,41 +201,4 @@ bool AsyncNameResolver::operator==(const AsyncNameResolver& resolver) const return this == &resolver; } -void AsyncNameResolver::reset() -{ - hostname_ = A2STR::NIL; - resolvedAddresses_.clear(); - status_ = STATUS_READY; - ares_destroy(channel_); - // TODO evaluate return value - ares_init(&channel_); -} - -#ifdef HAVE_ARES_ADDR_NODE - -ares_addr_node* parseAsyncDNSServers(const std::string& serversOpt) -{ - std::vector servers; - util::split(std::begin(serversOpt), std::end(serversOpt), - std::back_inserter(servers), ',', true /* doStrip */); - ares_addr_node root; - root.next = nullptr; - ares_addr_node* tail = &root; - for (const auto& s : servers) { - auto node = make_unique(); - - size_t len = net::getBinAddr(&node->addr, s.c_str()); - if (len != 0) { - node->next = nullptr; - node->family = (len == 4 ? AF_INET : AF_INET6); - tail->next = node.release(); - tail = tail->next; - } - } - - return root.next; -} - -#endif // HAVE_ARES_ADDR_NODE - } // namespace aria2 diff --git a/src/AsyncNameResolver.h b/src/AsyncNameResolver.h index 31a6ebe9..065ef534 100644 --- a/src/AsyncNameResolver.h +++ b/src/AsyncNameResolver.h @@ -46,9 +46,14 @@ namespace aria2 { +struct AsyncNameResolverSocketEntry { + int fd; + int events; +}; + class AsyncNameResolver { friend void callback(void* arg, int status, int timeouts, - struct hostent* host); + ares_addrinfo* result); public: enum STATUS { @@ -59,6 +64,7 @@ public: }; private: + std::vector socks_; STATUS status_; int family_; ares_channel channel_; @@ -68,12 +74,7 @@ private: std::string hostname_; public: - AsyncNameResolver(int family -#ifdef HAVE_ARES_ADDR_NODE - , - ares_addr_node* servers -#endif // HAVE_ARES_ADDR_NODE - ); + AsyncNameResolver(int family, const std::string& servers); ~AsyncNameResolver(); @@ -95,7 +96,7 @@ public: int getFamily() const { return family_; } #ifdef HAVE_LIBCARES - int getsock(sock_t* sockets) const; + const std::vector& getsock() const; void process(ares_socket_t readfd, ares_socket_t writefd); @@ -105,17 +106,11 @@ public: void setAddr(const std::string& addrString); - void reset(); - const std::string& getHostname() const { return hostname_; } + + void handle_sock_state(int sock, int read, int write); }; -#ifdef HAVE_ARES_ADDR_NODE - -ares_addr_node* parseAsyncDNSServers(const std::string& serversOpt); - -#endif // HAVE_ARES_ADDR_NODE - } // namespace aria2 #endif // D_ASYNC_NAME_RESOLVER_H diff --git a/src/AsyncNameResolverMan.cc b/src/AsyncNameResolverMan.cc index be073561..a9cb428c 100644 --- a/src/AsyncNameResolverMan.cc +++ b/src/AsyncNameResolverMan.cc @@ -88,12 +88,7 @@ void AsyncNameResolverMan::startAsyncFamily(const std::string& hostname, Command* command) { asyncNameResolver_[numResolver_] = - std::make_shared(family -#ifdef HAVE_ARES_ADDR_NODE - , - e->getAsyncDNSServers() -#endif // HAVE_ARES_ADDR_NODE - ); + std::make_shared(family, servers_); asyncNameResolver_[numResolver_]->resolve(hostname); setNameResolverCheck(numResolver_, e, command); } @@ -222,6 +217,7 @@ void configureAsyncNameResolverMan(AsyncNameResolverMan* asyncNameResolverMan, if (!net::getIPv6AddrConfigured() || option->getAsBool(PREF_DISABLE_IPV6)) { asyncNameResolverMan->setIPv6(false); } + asyncNameResolverMan->setServers(option->get(PREF_ASYNC_DNS_SERVER)); } } // namespace aria2 diff --git a/src/AsyncNameResolverMan.h b/src/AsyncNameResolverMan.h index 617474ec..b3133b98 100644 --- a/src/AsyncNameResolverMan.h +++ b/src/AsyncNameResolverMan.h @@ -79,6 +79,8 @@ public: // Resets state. Also removes resolvers from DownloadEngine. void reset(DownloadEngine* e, Command* command); + void setServers(std::string servers) { servers_ = std::move(servers); } + private: void startAsyncFamily(const std::string& hostname, int family, DownloadEngine* e, Command* command); @@ -88,6 +90,7 @@ private: Command* command); std::shared_ptr asyncNameResolver_[2]; + std::string servers_; size_t numResolver_; int resolverCheck_; bool ipv4_; diff --git a/src/DownloadEngine.cc b/src/DownloadEngine.cc index 2037f66f..8f392d11 100644 --- a/src/DownloadEngine.cc +++ b/src/DownloadEngine.cc @@ -104,9 +104,6 @@ DownloadEngine::DownloadEngine(std::unique_ptr eventPoll) #ifdef ENABLE_BITTORRENT btRegistry_(make_unique()), #endif // ENABLE_BITTORRENT -#ifdef HAVE_ARES_ADDR_NODE - asyncDNSServers_(nullptr), -#endif // HAVE_ARES_ADDR_NODE dnsCache_(make_unique()), option_(nullptr) { @@ -115,12 +112,7 @@ DownloadEngine::DownloadEngine(std::unique_ptr eventPoll) sessionId_.assign(&sessionId[0], &sessionId[sizeof(sessionId)]); } -DownloadEngine::~DownloadEngine() -{ -#ifdef HAVE_ARES_ADDR_NODE - setAsyncDNSServers(nullptr); -#endif // HAVE_ARES_ADDR_NODE -} +DownloadEngine::~DownloadEngine() {} namespace { void executeCommand(std::deque>& commands, @@ -612,19 +604,6 @@ void DownloadEngine::setCheckIntegrityMan( checkIntegrityMan_ = std::move(ciman); } -#ifdef HAVE_ARES_ADDR_NODE -void DownloadEngine::setAsyncDNSServers(ares_addr_node* asyncDNSServers) -{ - ares_addr_node* node = asyncDNSServers_; - while (node) { - ares_addr_node* next = node->next; - delete node; - node = next; - } - asyncDNSServers_ = asyncDNSServers; -} -#endif // HAVE_ARES_ADDR_NODE - #ifdef ENABLE_WEBSOCKET void DownloadEngine::setWebSocketSessionMan( std::unique_ptr wsman) diff --git a/src/DownloadEngine.h b/src/DownloadEngine.h index b544cfc6..c1c655c8 100644 --- a/src/DownloadEngine.h +++ b/src/DownloadEngine.h @@ -137,10 +137,6 @@ private: CUIDCounter cuidCounter_; -#ifdef HAVE_ARES_ADDR_NODE - ares_addr_node* asyncDNSServers_; -#endif // HAVE_ARES_ADDR_NODE - std::unique_ptr dnsCache_; std::unique_ptr authConfigFactory_; @@ -326,12 +322,6 @@ public: const std::string getSessionId() const { return sessionId_; } -#ifdef HAVE_ARES_ADDR_NODE - void setAsyncDNSServers(ares_addr_node* asyncDNSServers); - - ares_addr_node* getAsyncDNSServers() const { return asyncDNSServers_; } -#endif // HAVE_ARES_ADDR_NODE - #ifdef ENABLE_WEBSOCKET void setWebSocketSessionMan(std::unique_ptr wsman); const std::unique_ptr& diff --git a/src/Event.h b/src/Event.h index df8c4387..163552cf 100644 --- a/src/Event.h +++ b/src/Event.h @@ -293,16 +293,12 @@ private: Command* command_; - size_t socketsSize_; - - sock_t sockets_[ARES_GETSOCK_MAXNUM]; + std::vector sockets_; public: AsyncNameResolverEntry(std::shared_ptr nameResolver, Command* command) - : nameResolver_(std::move(nameResolver)), - command_(command), - socketsSize_(0) + : nameResolver_(std::move(nameResolver)), command_(command) { } @@ -323,33 +319,27 @@ public: void addSocketEvents(EventPoll* e) { - socketsSize_ = 0; - int mask = nameResolver_->getsock(sockets_); - if (mask == 0) { - return; - } - size_t i; - for (i = 0; i < ARES_GETSOCK_MAXNUM; ++i) { + const auto& socks = nameResolver_->getsock(); + sockets_.resize(socks.size()); + auto sock_it = std::begin(sockets_); + + for (const auto& ent : socks) { int events = 0; - if (ARES_GETSOCK_READABLE(mask, i)) { + if (ent.events & EventPoll::EVENT_READ) { events |= EventPoll::IEV_READ; } - if (ARES_GETSOCK_WRITABLE(mask, i)) { + if (ent.events & EventPoll::EVENT_WRITE) { events |= EventPoll::IEV_WRITE; } - if (events == 0) { - // assume no further sockets are returned. - break; - } - e->addEvents(sockets_[i], command_, events, nameResolver_); + e->addEvents(ent.fd, command_, events, nameResolver_); + *sock_it++ = ent.fd; } - socketsSize_ = i; } void removeSocketEvents(EventPoll* e) { - for (size_t i = 0; i < socketsSize_; ++i) { - e->deleteEvents(sockets_[i], command_, nameResolver_); + for (auto fd : sockets_) { + e->deleteEvents(fd, command_, nameResolver_); } } diff --git a/src/MultiUrlRequestInfo.cc b/src/MultiUrlRequestInfo.cc index 833188e3..46396f9c 100644 --- a/src/MultiUrlRequestInfo.cc +++ b/src/MultiUrlRequestInfo.cc @@ -272,11 +272,6 @@ int MultiUrlRequestInfo::prepare() clTlsContext->setVerifyPeer(option_->getAsBool(PREF_CHECK_CERTIFICATE)); SocketCore::setClientTLSContext(clTlsContext); #endif -#ifdef HAVE_ARES_ADDR_NODE - ares_addr_node* asyncDNSServers = - parseAsyncDNSServers(option_->get(PREF_ASYNC_DNS_SERVER)); - e_->setAsyncDNSServers(asyncDNSServers); -#endif // HAVE_ARES_ADDR_NODE std::string serverStatIf = option_->get(PREF_SERVER_STAT_IF); if (!serverStatIf.empty()) { diff --git a/src/OptionHandlerFactory.cc b/src/OptionHandlerFactory.cc index 2cd2c43e..000426b6 100644 --- a/src/OptionHandlerFactory.cc +++ b/src/OptionHandlerFactory.cc @@ -99,15 +99,13 @@ std::vector OptionHandlerFactory::createOptionHandlers() op->setChangeOptionForReserved(true); handlers.push_back(op); } -# if defined(HAVE_ARES_SET_SERVERS) && defined(HAVE_ARES_ADDR_NODE) { OptionHandler* op(new DefaultOptionHandler( PREF_ASYNC_DNS_SERVER, TEXT_ASYNC_DNS_SERVER, NO_DEFAULT_VALUE)); op->addTag(TAG_ADVANCED); handlers.push_back(op); } -# endif // HAVE_ARES_SET_SERVERS && HAVE_ARES_ADDR_NODE -#endif // ENABLE_ASYNC_DNS +#endif // ENABLE_ASYNC_DNS { OptionHandler* op(new BooleanOptionHandler( PREF_AUTO_FILE_RENAMING, TEXT_AUTO_FILE_RENAMING, A2_V_TRUE, diff --git a/test/AsyncNameResolverTest.cc b/test/AsyncNameResolverTest.cc index 0c793bc8..23518d37 100644 --- a/test/AsyncNameResolverTest.cc +++ b/test/AsyncNameResolverTest.cc @@ -11,43 +11,14 @@ namespace aria2 { class AsyncNameResolverTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(AsyncNameResolverTest); - CPPUNIT_TEST(testParseAsyncDNSServers); CPPUNIT_TEST_SUITE_END(); public: void setUp() {} void tearDown() {} - - void testParseAsyncDNSServers(); }; CPPUNIT_TEST_SUITE_REGISTRATION(AsyncNameResolverTest); -void AsyncNameResolverTest::testParseAsyncDNSServers() -{ -#ifdef HAVE_ARES_ADDR_NODE - in_addr ans4; - CPPUNIT_ASSERT_EQUAL((size_t)4, net::getBinAddr(&ans4, "192.168.0.1")); - in6_addr ans6; - CPPUNIT_ASSERT_EQUAL((size_t)16, net::getBinAddr(&ans6, "2001:db8::2:1")); - - ares_addr_node* root; - root = parseAsyncDNSServers("192.168.0.1,2001:db8::2:1"); - ares_addr_node* node = root; - CPPUNIT_ASSERT(node); - CPPUNIT_ASSERT_EQUAL(AF_INET, node->family); - CPPUNIT_ASSERT(memcmp(&ans4, &node->addr, sizeof(ans4)) == 0); - node = node->next; - CPPUNIT_ASSERT(node); - CPPUNIT_ASSERT_EQUAL(AF_INET6, node->family); - CPPUNIT_ASSERT(memcmp(&ans6, &node->addr, sizeof(ans6)) == 0); - for (node = root; node;) { - ares_addr_node* nextNode = node->next; - delete node; - node = nextNode; - } -#endif // HAVE_ARES_ADDR_NODE -} - } // namespace aria2