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

libtorrent: Optimize UDP trackers for UDNS #42

Merged
merged 1 commit into from
Jul 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 19 additions & 0 deletions libtorrent/rak/socket_address.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ class socket_address_inet {
bool is_port_any() const { return port() == 0; }
bool is_address_any() const { return m_sockaddr.sin_addr.s_addr == htonl(INADDR_ANY); }

#ifdef USE_UDNS
bool is_bindable() const { return !is_address_any(); }
#endif

void clear() { std::memset(this, 0, sizeof(socket_address_inet)); set_family(); }

uint16_t port() const { return ntohs(m_sockaddr.sin_port); }
Expand All @@ -168,6 +172,10 @@ class socket_address_inet {
uint32_t address_n() const { return m_sockaddr.sin_addr.s_addr; }
std::string address_str() const;
bool address_c_str(char* buf, socklen_t size) const;

#ifdef USE_UDNS
std::string pretty_address_str() const { return address_str(); }
#endif

void set_address(in_addr a) { m_sockaddr.sin_addr = a; }
void set_address_h(uint32_t a) { m_sockaddr.sin_addr.s_addr = htonl(a); }
Expand All @@ -180,13 +188,24 @@ class socket_address_inet {
sa_family_t family() const { return m_sockaddr.sin_family; }
void set_family() { m_sockaddr.sin_family = AF_INET; }

#ifdef USE_UDNS
uint32_t length() const { return sizeof(sockaddr_in); }
#endif

sockaddr* c_sockaddr() { return reinterpret_cast<sockaddr*>(&m_sockaddr); }
sockaddr_in* c_sockaddr_inet() { return &m_sockaddr; }

const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddr; }

socket_address_inet6 to_mapped_address() const;

#ifdef USE_UDNS
static socket_address_inet* cast_from(sockaddr* sa) { return reinterpret_cast<socket_address_inet*>(sa); }
static const socket_address_inet* cast_from(const sockaddr* sa) { return reinterpret_cast<const socket_address_inet*>(sa); }
static socket_address_inet* cast_from_inet(sockaddr_in* sa) { return reinterpret_cast<socket_address_inet*>(sa); }
static const socket_address_inet* cast_from_inet(const sockaddr_in* sa) { return reinterpret_cast<const socket_address_inet*>(sa); }
#endif

bool operator == (const socket_address_inet& rhs) const;
bool operator < (const socket_address_inet& rhs) const;
Expand Down
2 changes: 1 addition & 1 deletion libtorrent/src/net/socket_datagram.cc
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ SocketDatagram::write_datagram(const void* buffer, unsigned int length, rak::soc

#ifdef USE_UDNS
int
SocketDatagram::write_datagram_ipv4(const void* buffer, unsigned int length, rak::socket_address* sa) {
SocketDatagram::write_datagram_ipv4(const void* buffer, unsigned int length, rak::socket_address_inet* sa) {
if (length == 0)
throw internal_error("Tried to send buffer length 0");

Expand Down
2 changes: 1 addition & 1 deletion libtorrent/src/net/socket_datagram.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class SocketDatagram : public SocketBase {
int read_datagram(void* buffer, unsigned int length, rak::socket_address* sa = NULL);
int write_datagram(const void* buffer, unsigned int length, rak::socket_address* sa = NULL);
#ifdef USE_UDNS
int write_datagram_ipv4(const void* buffer, unsigned int length, rak::socket_address* sa = NULL);
int write_datagram_ipv4(const void* buffer, unsigned int length, rak::socket_address_inet* sa = NULL);
#endif
};

Expand Down
2 changes: 1 addition & 1 deletion libtorrent/src/net/socket_fd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ SocketFd::bind(const rak::socket_address& sa) {

#ifdef USE_UDNS
bool
SocketFd::bind_ipv4(const rak::socket_address& sa) {
SocketFd::bind_ipv4(const rak::socket_address_inet& sa) {
check_valid();

return !::bind(m_fd, sa.c_sockaddr(), sa.length());
Expand Down
5 changes: 4 additions & 1 deletion libtorrent/src/net/socket_fd.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@

namespace rak {
class socket_address;
#ifdef USE_UDNS
class socket_address_inet;
#endif
}

namespace torrent {
Expand Down Expand Up @@ -88,7 +91,7 @@ class SocketFd {
bool getsockname(rak::socket_address* sa);

#ifdef USE_UDNS
bool bind_ipv4(const rak::socket_address& sa);
bool bind_ipv4(const rak::socket_address_inet& sa);
#endif

bool listen(int size);
Expand Down
10 changes: 7 additions & 3 deletions libtorrent/src/torrent/connection_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ class UdnsAsyncResolver : public AsyncResolver {
public:
UdnsAsyncResolver(ConnectionManager *cm) : AsyncResolver(cm) {}

void *enqueue(const char *name, int family, resolver_callback *cbck) {
return m_udnsevent.enqueue_resolve(name, family, cbck);
void *enqueue(const char *name, resolver_callback *cbck) {
return m_udnsevent.enqueue_resolve(name, cbck);
}

void flush() {
Expand All @@ -79,7 +79,7 @@ class UdnsAsyncResolver : public AsyncResolver {
};

void
ConnectionManager::start_udp_announce(uint64_t idx, const sockaddr* sa, int err) {
ConnectionManager::start_udp_announce(uint64_t idx, const sockaddr_in* sa, int err) {
if (m_tracker_udp_list[idx] != NULL) {
m_tracker_udp_list[idx]->start_announce(sa, err);
}
Expand Down Expand Up @@ -135,7 +135,11 @@ class StubAsyncResolver : public AsyncResolver {
#endif

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

Expand Down
19 changes: 14 additions & 5 deletions libtorrent/src/torrent/connection_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,12 @@ 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.
#ifdef USE_UDNS
typedef std::function<void (const sockaddr_in*, int)> resolver_callback;
typedef std::function<void (const sockaddr*, int)> legacy_resolver_callback;
#else
typedef std::function<void (const sockaddr*, int)> resolver_callback;
#endif

// Encapsulates whether we do genuine async resolution or fall back to sync.
// In a build with USE_UDNS, these do genuine asynchronous DNS resolution.
Expand All @@ -74,7 +79,11 @@ class LIBTORRENT_EXPORT AsyncResolver {
// 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):
#ifdef USE_UDNS
virtual void* enqueue(const char *name, resolver_callback *cbck) = 0;
#else
virtual void* enqueue(const char *name, int family, resolver_callback *cbck) = 0;
#endif
// this sends any queued resolves. it can execute arbitrary callbacks
// before returning control:
virtual void flush() = 0;
Expand Down Expand Up @@ -130,7 +139,11 @@ class LIBTORRENT_EXPORT ConnectionManager {
typedef std::function<uint32_t (const sockaddr*)> slot_filter_type;
typedef std::function<ThrottlePair (const sockaddr*)> slot_throttle_type;

#ifdef USE_UDNS
typedef std::function<void (const char*, int, int, legacy_resolver_callback)> slot_resolver_type;
#else
typedef std::function<void (const char*, int, int, resolver_callback)> slot_resolver_type;
#endif

ConnectionManager();
~ConnectionManager();
Expand Down Expand Up @@ -182,12 +195,8 @@ class LIBTORRENT_EXPORT ConnectionManager {
void set_listen_port(port_type p) { m_listen_port = p; }
void set_listen_backlog(int v);

void* enqueue_async_resolve(const char *name, int family, resolver_callback *cbck);
void flush_async_resolves();
void cancel_async_resolve(void *query);

#ifdef USE_UDNS
void start_udp_announce(uint64_t idx, const sockaddr* sa, int err);
void start_udp_announce(uint64_t idx, const sockaddr_in* sa, int err);
void null_udp_tracker(uint64_t idx) { m_tracker_udp_list[idx] = NULL; }
void add_udp_tracker(TrackerUdp* tracker) { m_tracker_udp_list.push_back(tracker); }
uint64_t get_udp_tracker_count() { return m_tracker_udp_list.size(); }
Expand Down
50 changes: 41 additions & 9 deletions libtorrent/src/tracker/tracker_udp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -110,24 +110,25 @@ TrackerUdp::send_state(int state) {

m_resolver_query = manager->connection_manager()->async_resolver().enqueue(
m_hostname.c_str(),
AF_UNSPEC,
#ifdef USE_UDNS
manager->connection_manager()->get_resolver_callback(m_vec_idx)
#else
AF_UNSPEC,
&m_resolver_callback
#endif
);
manager->connection_manager()->async_resolver().flush();
}

#ifdef USE_UDNS
void
TrackerUdp::start_announce(const sockaddr* sa, int err) {
TrackerUdp::start_announce(const sockaddr_in* sa, int err) {
m_resolver_query = NULL;

if (sa == NULL)
return receive_failed("could not resolve hostname");

m_connectAddress = *rak::socket_address::cast_from(sa);
m_connectAddress = *rak::socket_address_inet::cast_from_inet(sa);
m_connectAddress.set_port(m_port);

LT_LOG_TRACKER(DEBUG, "address found (address:%s)", m_connectAddress.address_str().c_str());
Expand All @@ -136,20 +137,50 @@ TrackerUdp::start_announce(const sockaddr* sa, int err) {
return receive_failed("invalid tracker address");

// TODO: Make each of these a separate error... at the very least separate open and bind.
#ifdef USE_UDNS
if (!get_fd().open_datagram_ipv4() || !get_fd().set_nonblock())
return receive_failed("could not open UDP socket");

auto bind_address = rak::socket_address_inet::cast_from(manager->connection_manager()->bind_address());

if (bind_address->is_bindable() && !get_fd().bind_ipv4(*bind_address))
return receive_failed("failed to bind socket to udp address '" + bind_address->pretty_address_str() + "' with error '" + rak::error_number::current().c_str() + "'");

m_readBuffer = new ReadBuffer;
m_writeBuffer = new WriteBuffer;

prepare_connect_input();

manager->poll()->open(this);
manager->poll()->insert_read(this);
manager->poll()->insert_write(this);
manager->poll()->insert_error(this);

m_tries = m_parent->info()->udp_tries();
priority_queue_insert(&taskScheduler, &m_taskTimeout, (cachedTime + rak::timer::from_seconds(m_parent->info()->udp_timeout())).round_seconds());
}
#else
void
TrackerUdp::start_announce(const sockaddr* sa, int err) {
m_resolver_query = NULL;

if (sa == NULL)
return receive_failed("could not resolve hostname");

m_connectAddress = *rak::socket_address::cast_from(sa);
m_connectAddress.set_port(m_port);

LT_LOG_TRACKER(DEBUG, "address found (address:%s)", m_connectAddress.address_str().c_str());

if (!m_connectAddress.is_valid())
return receive_failed("invalid tracker address");

// TODO: Make each of these a separate error... at the very least separate open and bind.
if (!get_fd().open_datagram() || !get_fd().set_nonblock())
#endif
return receive_failed("could not open UDP socket");

auto bind_address = rak::socket_address::cast_from(manager->connection_manager()->bind_address());

#ifdef USE_UDNS
if (bind_address->is_bindable() && !get_fd().bind_ipv4(*bind_address))
#else
if (bind_address->is_bindable() && !get_fd().bind(*bind_address))
#endif
return receive_failed("failed to bind socket to udp address '" + bind_address->pretty_address_str() + "' with error '" + rak::error_number::current().c_str() + "'");

m_readBuffer = new ReadBuffer;
Expand All @@ -165,6 +196,7 @@ TrackerUdp::start_announce(const sockaddr* sa, int err) {
m_tries = m_parent->info()->udp_tries();
priority_queue_insert(&taskScheduler, &m_taskTimeout, (cachedTime + rak::timer::from_seconds(m_parent->info()->udp_timeout())).round_seconds());
}
#endif

void
TrackerUdp::close() {
Expand Down
11 changes: 10 additions & 1 deletion libtorrent/src/tracker/tracker_udp.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,12 @@ class TrackerUdp : public SocketDatagram, public Tracker {
virtual void event_read();
virtual void event_write();
virtual void event_error();


#ifdef USE_UDNS
void start_announce(const sockaddr_in* sa, int err);
#else
void start_announce(const sockaddr* sa, int err);
#endif

private:
void close_directly();
Expand All @@ -93,7 +97,12 @@ class TrackerUdp : public SocketDatagram, public Tracker {

bool parse_udp_url(const std::string& url, hostname_type& hostname, int& port) const;

#ifdef USE_UDNS
rak::socket_address_inet m_connectAddress;
#else
rak::socket_address m_connectAddress;
#endif

int m_port;
std::string m_hostname;

Expand Down
Loading
Loading