Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

async DNS resolution via udns, take 3 #134

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e489e71
asynchronous DNS resolution support via udns
slingamn Nov 10, 2016
c004a60
udns and non-udns travis builds
slingamn Nov 10, 2016
48ffa56
give MockResolve a real constructor
slingamn Nov 11, 2016
803907e
make udns an automatic/optional dependency by default
slingamn Nov 11, 2016
1a8c250
review fixes
slingamn Nov 14, 2016
719dd39
fix inconsistent indentation
slingamn Nov 14, 2016
ae09b21
fix incorrect ordering of cancel / callback execution / free in udnse…
slingamn Nov 16, 2016
5ca51d3
review fixes
slingamn Nov 17, 2016
d20ec47
de-indent udnsevent.cc (namespaces are not indented)
slingamn Nov 22, 2016
3e20053
review fixes
slingamn Nov 22, 2016
e2360fd
use std::unique_ptr to manage the mock resolve structs
slingamn Nov 22, 2016
98ea519
rename a variable to avoid confusion
slingamn Nov 23, 2016
ca8afa3
Refactor interface to reduce #ifdefs
slingamn Dec 4, 2016
da3a4c9
Merge remote-tracking branch 'origin/master' into udns.137.fall2019
slingamn Sep 15, 2019
eacec4b
fix compilation errors
slingamn Sep 15, 2019
f84a09e
Merge remote-tracking branch 'origin/master' into udns.137.april2020
slingamn Mar 30, 2020
058db13
fix compatibility with new makefile consolidation
slingamn Mar 30, 2020
e2a5d8b
Merge remote-tracking branch 'origin/master' into udns.137.may2022
slingamn May 8, 2022
b168631
Merge remote-tracking branch 'origin/master' into udns.137.june2023
slingamn Jun 11, 2023
2510069
only resolve UDP trackers to their IPv4 addresses
slingamn Jun 11, 2023
a03859e
Merge branch 'udns.137.june2023' into udns.140
slingamn Nov 10, 2024
3da9490
remove dead code
slingamn Nov 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ scripts/lt*.m4
.#*
\#*#
*~
*.swp

# Packages #
############
Expand Down
27 changes: 26 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,19 @@ matrix:
include:
- compiler: clang
env: COMPILER=clang++ SKIP_CHECK=true SKIP_COVERAGE=true
addons:
apt:
packages:
- libudns-dev
- compiler: clang
env: COMPILER=clang++ SKIP_COVERAGE=true
addons:
apt:
packages:
- libcppunit-dev
- libudns-dev
- compiler: clang
env: COMPILER=clang++ SKIP_COVERAGE=true UDNS=--disable-udns
addons:
apt:
packages:
Expand All @@ -20,6 +31,7 @@ matrix:
packages:
- clang-3.6
- libcppunit-dev
- libudns-dev
- compiler: clang
env: COMPILER=clang++-3.7 SKIP_COVERAGE=true
addons:
Expand All @@ -30,6 +42,7 @@ matrix:
packages:
- clang-3.7
- libcppunit-dev
- libudns-dev
- compiler: clang
env: COMPILER=clang++-3.8 SKIP_COVERAGE=true
addons:
Expand All @@ -40,15 +53,26 @@ matrix:
packages:
- clang-3.8
- libcppunit-dev
- libudns-dev
- compiler: gcc
env: COMPILER=g++-4.7 SKIP_CHECK=true SKIP_COVERAGE=true
addons:
apt:
sources: ubuntu-toolchain-r-test
packages:
- g++-4.7
- libudns-dev
- compiler: gcc
env: COMPILER=g++-4.7 SKIP_COVERAGE=true
addons:
apt:
sources: ubuntu-toolchain-r-test
packages:
- g++-4.7
- libcppunit-dev
- libudns-dev
- compiler: gcc
env: COMPILER=g++-4.7 SKIP_COVERAGE=true UDNS=--disable-udns
addons:
apt:
sources: ubuntu-toolchain-r-test
Expand All @@ -63,13 +87,14 @@ matrix:
packages:
- g++-4.8
- libcppunit-dev
- libudns-dev

before_install:
- if [ ! $SKIP_COVERAGE ]; then pip install --user cpp-coveralls; fi

script:
- if [ ! $SKIP_COVERAGE ]; then export CXXFLAGS="-ftest-coverage -fprofile-arcs"; fi
- ./autogen.sh && CXX="$COMPILER" ./configure && make -j12
- ./autogen.sh && CXX="$COMPILER" ./configure $UDNS && make -j12
- if [ ! $SKIP_CHECK ]; then make -j12 check; fi

after_success:
Expand Down
2 changes: 2 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ AC_ARG_ENABLE(cyrus-rc4,
]
)

TORRENT_WITH_UDNS()

AC_CHECK_FUNCS(posix_memalign)

TORRENT_CHECK_MADVISE()
Expand Down
26 changes: 26 additions & 0 deletions scripts/udns.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
dnl function for enabling/disabling udns support
AC_DEFUN([TORRENT_WITH_UDNS], [
AC_ARG_WITH(
[udns],
AS_HELP_STRING([--without-udns], [Don't use udns, falling back to synchronous DNS resolution.])
)
dnl neither ubuntu nor fedora ships a pkgconfig file for udns
AS_IF(
[test "x$with_udns" != "xno"],
[AC_CHECK_HEADERS([udns.h], [have_udns=yes], [have_udns=no])],
[have_udns=no]
)
AS_IF(
[test "x$have_udns" = "xyes"],
[
AC_DEFINE(USE_UDNS, 1, Define to build with udns support.)
LIBS="$LIBS -ludns"
],
[
AS_IF(
[test "x$with_udns" = "xyes"],
[AC_MSG_ERROR([udns requested but not found])]
)
]
)
])
85 changes: 79 additions & 6 deletions src/torrent/connection_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,69 @@
#include "exceptions.h"
#include "manager.h"

#ifdef USE_UDNS
#include "utils/udnsevent.h"
#endif

namespace torrent {

// Fix TrackerUdp, etc, if this is made async.
static ConnectionManager::slot_resolver_result_type*
resolve_host(const char* host, int family, int socktype, ConnectionManager::slot_resolver_result_type slot) {
/* Encapsulates whether we do genuine async resolution or fall back to sync. */
struct AsyncResolver {

ConnectionManager *m_connection_manager;
#ifdef USE_UDNS
UdnsEvent m_udnsevent;
#else
struct MockResolve {
std::string hostname;
int family;
resolver_callback *callback;
};
std::list<MockResolve*> m_mock_resolve_queue;
#endif

AsyncResolver(ConnectionManager *cm): m_connection_manager(cm) {}

void *enqueue_resolve(const char *name, int family, resolver_callback *cbck) {
#ifdef USE_UDNS
return m_udnsevent.enqueue_resolve(name, family, cbck);
#else
MockResolve *mock_resolve = new MockResolve {name, family, cbck};
m_mock_resolve_queue.push_back(mock_resolve);
return mock_resolve;
#endif
}

void flush_resolves() {
#ifdef USE_UDNS
m_udnsevent.flush_resolves();
#else
// dequeue all callbacks and resolve them synchronously
while (!m_mock_resolve_queue.empty()) {
MockResolve *mock_resolve = m_mock_resolve_queue.front();
m_mock_resolve_queue.pop_front();
m_connection_manager->resolver()(mock_resolve->hostname.c_str(), mock_resolve->family, 0, *(mock_resolve->callback));
delete mock_resolve;
}
#endif
}

void cancel_resolve(void *query) {
#ifdef USE_UDNS
m_udnsevent.cancel(static_cast<UdnsQuery*>(query));
#else
MockResolve *mock_resolve = static_cast<MockResolve*>(query);
auto it = std::find(std::begin(m_mock_resolve_queue), std::end(m_mock_resolve_queue), mock_resolve);
if (it != std::end(m_mock_resolve_queue)) {
m_mock_resolve_queue.erase(it);
delete mock_resolve;
}
#endif
}
};
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems a bit too much to include in this file, consider moving it to a source file in the same place as the udns stuff is.


static void
resolve_host(const char* host, int family, int socktype, resolver_callback slot) {
if (manager->main_thread_main()->is_current())
thread_base::release_global_lock();

Expand All @@ -64,7 +122,7 @@ resolve_host(const char* host, int family, int socktype, ConnectionManager::slot
thread_base::acquire_global_lock();

slot(NULL, err);
return NULL;
return;
}

rak::socket_address sa;
Expand All @@ -75,7 +133,7 @@ resolve_host(const char* host, int family, int socktype, ConnectionManager::slot
thread_base::acquire_global_lock();

slot(sa.c_sockaddr(), 0);
return NULL;
return;
}

ConnectionManager::ConnectionManager() :
Expand All @@ -89,7 +147,8 @@ ConnectionManager::ConnectionManager() :

m_listen(new Listen),
m_listen_port(0),
m_listen_backlog(SOMAXCONN) {
m_listen_backlog(SOMAXCONN),
m_async_resolver(new AsyncResolver(this)) {

m_bindAddress = (new rak::socket_address())->c_sockaddr();
m_localAddress = (new rak::socket_address())->c_sockaddr();
Expand Down Expand Up @@ -202,4 +261,18 @@ ConnectionManager::set_listen_backlog(int v) {
m_listen_backlog = v;
}

void *
ConnectionManager::enqueue_async_resolve(const char *name, int family, resolver_callback *cbck) {
return m_async_resolver->enqueue_resolve(name, family, cbck);
}

void ConnectionManager::flush_async_resolves() {
m_async_resolver->flush_resolves();
}

void
ConnectionManager::cancel_async_resolve(void *query) {
m_async_resolver->cancel_resolve(query);
}

}
36 changes: 28 additions & 8 deletions src/torrent/connection_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,13 @@
#ifndef LIBTORRENT_CONNECTION_MANAGER_H
#define LIBTORRENT_CONNECTION_MANAGER_H

#include <list>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <list>
#include <memory>
#include lt_tr1_functional
#include <torrent/common.h>

Expand All @@ -54,6 +55,12 @@ namespace torrent {
// First element is upload throttle, second element is download throttle.
typedef std::pair<Throttle*, Throttle*> ThrottlePair;

// The sockaddr argument in the result call is NULL if the resolve failed,
// and the int holds the error code.
typedef std::function<void (const sockaddr*, int)> resolver_callback;

struct AsyncResolver;

class LIBTORRENT_EXPORT ConnectionManager {
public:
typedef uint32_t size_type;
Expand Down Expand Up @@ -100,9 +107,7 @@ class LIBTORRENT_EXPORT ConnectionManager {
typedef std::function<uint32_t (const sockaddr*)> slot_filter_type;
typedef std::function<ThrottlePair (const sockaddr*)> slot_throttle_type;

// The sockaddr argument in the result slot call is NULL if the resolve failed, and the int holds the errno.
typedef std::function<void (const sockaddr*, int)> slot_resolver_result_type;
typedef std::function<slot_resolver_result_type* (const char*, int, int, slot_resolver_result_type)> slot_resolver_type;
typedef std::function<void (const char*, int, int, resolver_callback)> slot_resolver_type;

ConnectionManager();
~ConnectionManager();
Expand Down Expand Up @@ -154,10 +159,23 @@ class LIBTORRENT_EXPORT ConnectionManager {
void set_listen_port(port_type p) { m_listen_port = p; }
void set_listen_backlog(int v);

// The resolver returns a pointer to its copy of the result slot
// which the caller may set blocked to prevent the slot from being
// called. The pointer must be NULL if the result slot was already
// called because the resolve was synchronous.
/* Async resolver interface.

In a build with USE_UDNS, these do genuine asynchronous DNS resolution.
In a build without it, they're stubbed out to use a synchronous getaddrinfo(3)
call, while exposing the same API.
*/
// this queues a DNS resolve but doesn't send it. it doesn't execute any callbacks
// and returns control immediately. the return value is an opaque identifier that
// can be used to cancel the query (as long as the callback hasn't been executed yet):
void* enqueue_async_resolve(const char *name, int family, resolver_callback *cbck);
// this sends any queued resolves. it can execute arbitrary callbacks
// before returning control:
void flush_async_resolves();
// this cancels a pending async query (as long as the callback hasn't executed yet):
void cancel_async_resolve(void *query);

/* Legacy synchronous resolver interface. */
slot_resolver_type& resolver() { return m_slot_resolver; }

// The slot returns a ThrottlePair to use for the given address, or
Expand Down Expand Up @@ -190,6 +208,8 @@ class LIBTORRENT_EXPORT ConnectionManager {
slot_filter_type m_slot_filter;
slot_resolver_type m_slot_resolver;
slot_throttle_type m_slot_address_throttle;

std::unique_ptr<AsyncResolver> m_async_resolver;
};

}
Expand Down
Loading