From 544ed0ca1638a52125b07c36eaa58942deb880d6 Mon Sep 17 00:00:00 2001 From: stickz Date: Tue, 16 Jul 2024 16:41:52 -0400 Subject: [PATCH] libtorrent: Use UDNS static cast (#34) --- libtorrent/rak/socket_address.h | 7 ++- libtorrent/src/net/socket_datagram.cc | 34 +++++++++++++++ libtorrent/src/net/socket_datagram.h | 3 ++ libtorrent/src/torrent/connection_manager.cc | 6 +-- libtorrent/src/torrent/connection_manager.h | 7 +-- libtorrent/src/tracker/tracker_udp.cc | 11 +++-- libtorrent/src/tracker/tracker_udp.h | 6 +-- libtorrent/src/utils/udnsevent.cc | 45 +------------------- libtorrent/src/utils/udnsevent.h | 4 +- 9 files changed, 62 insertions(+), 61 deletions(-) diff --git a/libtorrent/rak/socket_address.h b/libtorrent/rak/socket_address.h index 961c53b24..b46006374 100644 --- a/libtorrent/rak/socket_address.h +++ b/libtorrent/rak/socket_address.h @@ -127,6 +127,9 @@ class socket_address { static socket_address* cast_from(sockaddr* sa) { return reinterpret_cast(sa); } static const socket_address* cast_from(const sockaddr* sa) { return reinterpret_cast(sa); } + + static socket_address_inet* cast_from_in(sockaddr_in* sa) { return reinterpret_cast(sa); } + static const socket_address_inet* cast_from_in(const sockaddr_in* sa) { return reinterpret_cast(sa); } // The different families will be sorted according to the // sa_family_t's numeric value. @@ -161,7 +164,9 @@ class socket_address_inet { uint16_t port_n() const { return m_sockaddr.sin_port; } void set_port(uint16_t p) { m_sockaddr.sin_port = htons(p); } void set_port_n(uint16_t p) { m_sockaddr.sin_port = p; } - + + uint32_t length() const { return sizeof(sockaddr_in); } + // Should address() return the uint32_t? in_addr address() const { return m_sockaddr.sin_addr; } uint32_t address_h() const { return ntohl(m_sockaddr.sin_addr.s_addr); } diff --git a/libtorrent/src/net/socket_datagram.cc b/libtorrent/src/net/socket_datagram.cc index e7c5e1a55..7d8d3166b 100644 --- a/libtorrent/src/net/socket_datagram.cc +++ b/libtorrent/src/net/socket_datagram.cc @@ -86,4 +86,38 @@ SocketDatagram::write_datagram(const void* buffer, unsigned int length, rak::soc return r; } +int +SocketDatagram::read_datagram_inet(void* buffer, unsigned int length, rak::socket_address_inet* sa) { + if (length == 0) + throw internal_error("Tried to receive buffer length 0"); + + int r; + socklen_t fromlen; + + if (sa != NULL) { + fromlen = sizeof(rak::socket_address); + r = ::recvfrom(m_fileDesc, buffer, length, 0, sa->c_sockaddr(), &fromlen); + } else { + r = ::recv(m_fileDesc, buffer, length, 0); + } + + return r; +} + +int +SocketDatagram::write_datagram_inet(const void* buffer, unsigned int length, rak::socket_address_inet* sa) { + if (length == 0) + throw internal_error("Tried to send buffer length 0"); + + int r; + + if (sa != NULL) { + r = ::sendto(m_fileDesc, buffer, length, 0, sa->c_sockaddr(), sa->length()); + } else { + r = ::send(m_fileDesc, buffer, length, 0); + } + + return r; +} + } diff --git a/libtorrent/src/net/socket_datagram.h b/libtorrent/src/net/socket_datagram.h index 47649f554..de477f755 100644 --- a/libtorrent/src/net/socket_datagram.h +++ b/libtorrent/src/net/socket_datagram.h @@ -48,6 +48,9 @@ class SocketDatagram : public SocketBase { // used. 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); + + int read_datagram_inet(void* buffer, unsigned int length, rak::socket_address_inet* sa = NULL); + int write_datagram_inet(const void* buffer, unsigned int length, rak::socket_address_inet* sa = NULL); }; } diff --git a/libtorrent/src/torrent/connection_manager.cc b/libtorrent/src/torrent/connection_manager.cc index f1a5778a6..ebf6dd539 100644 --- a/libtorrent/src/torrent/connection_manager.cc +++ b/libtorrent/src/torrent/connection_manager.cc @@ -61,7 +61,7 @@ class UdnsAsyncResolver : public AsyncResolver { public: UdnsAsyncResolver(ConnectionManager *cm) : AsyncResolver(cm) {} - void *enqueue(const char *name, int family, resolver_callback *cbck) { + void *enqueue(const char *name, int family, async_resolver_callback *cbck) { return m_udnsevent.enqueue_resolve(name, family, cbck); } @@ -83,12 +83,12 @@ class StubAsyncResolver : public AsyncResolver { struct mock_resolve { std::string hostname; int family; - resolver_callback *callback; + async_resolver_callback *callback; }; StubAsyncResolver(ConnectionManager *cm): AsyncResolver(cm), m_connection_manager(cm) {} - void *enqueue(const char *name, int family, resolver_callback *cbck) { + void *enqueue(const char *name, int family, async_resolver_callback *cbck) { mock_resolve *mr = new mock_resolve {name, family, cbck}; m_mock_resolve_queue.emplace_back(mr); return mr; diff --git a/libtorrent/src/torrent/connection_manager.h b/libtorrent/src/torrent/connection_manager.h index bed441ca7..8b1ff5070 100644 --- a/libtorrent/src/torrent/connection_manager.h +++ b/libtorrent/src/torrent/connection_manager.h @@ -57,7 +57,8 @@ typedef std::pair ThrottlePair; // The sockaddr argument in the result call is NULL if the resolve failed, // and the int holds the error code. -typedef std::function resolver_callback; +typedef std::function resolver_callback; +typedef std::function async_resolver_callback; // Encapsulates whether we do genuine async resolution or fall back to sync. // In a build with USE_UDNS, these do genuine asynchronous DNS resolution. @@ -70,7 +71,7 @@ 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): - virtual void* enqueue(const char *name, int family, resolver_callback *cbck) = 0; + virtual void* enqueue(const char *name, int family, async_resolver_callback *cbck) = 0; // this sends any queued resolves. it can execute arbitrary callbacks // before returning control: virtual void flush() = 0; @@ -178,7 +179,7 @@ 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* enqueue_async_resolve(const char *name, int family, async_resolver_callback *cbck); void flush_async_resolves(); void cancel_async_resolve(void *query); diff --git a/libtorrent/src/tracker/tracker_udp.cc b/libtorrent/src/tracker/tracker_udp.cc index e50b51bd3..2a0b24113 100644 --- a/libtorrent/src/tracker/tracker_udp.cc +++ b/libtorrent/src/tracker/tracker_udp.cc @@ -107,13 +107,13 @@ TrackerUdp::send_state(int state) { } 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::cast_from_in(sa); m_connectAddress.set_port(m_port); LT_LOG_TRACKER(DEBUG, "address found (address:%s)", m_connectAddress.address_str().c_str()); @@ -209,9 +209,8 @@ TrackerUdp::receive_timeout() { void TrackerUdp::event_read() { - rak::socket_address sa; - - int s = read_datagram(m_readBuffer->begin(), m_readBuffer->reserved(), &sa); + rak::socket_address_inet sa; + int s = read_datagram_inet(m_readBuffer->begin(), m_readBuffer->reserved(), &sa); if (s < 0) return; @@ -262,7 +261,7 @@ TrackerUdp::event_write() { if (m_writeBuffer->size_end() == 0) throw internal_error("TrackerUdp::write() called but the write buffer is empty."); - int __UNUSED s = write_datagram(m_writeBuffer->begin(), m_writeBuffer->size_end(), &m_connectAddress); + int __UNUSED s = write_datagram_inet(m_writeBuffer->begin(), m_writeBuffer->size_end(), &m_connectAddress); manager->poll()->remove_write(this); } diff --git a/libtorrent/src/tracker/tracker_udp.h b/libtorrent/src/tracker/tracker_udp.h index d0be6376d..ad2e260bb 100644 --- a/libtorrent/src/tracker/tracker_udp.h +++ b/libtorrent/src/tracker/tracker_udp.h @@ -82,7 +82,7 @@ class TrackerUdp : public SocketDatagram, public Tracker { void receive_failed(const std::string& msg); void receive_timeout(); - void start_announce(const sockaddr* sa, int err); + void start_announce(const sockaddr_in* sa, int err); void prepare_connect_input(); void prepare_announce_input(); @@ -93,13 +93,13 @@ class TrackerUdp : public SocketDatagram, public Tracker { bool parse_udp_url(const std::string& url, hostname_type& hostname, int& port) const; - rak::socket_address m_connectAddress; + rak::socket_address_inet m_connectAddress; int m_port; std::string m_hostname; int m_sendState; - resolver_callback m_resolver_callback; + async_resolver_callback m_resolver_callback; void* m_resolver_query; uint32_t m_action; diff --git a/libtorrent/src/utils/udnsevent.cc b/libtorrent/src/utils/udnsevent.cc index 7162d970c..e9b63da21 100644 --- a/libtorrent/src/utils/udnsevent.cc +++ b/libtorrent/src/utils/udnsevent.cc @@ -57,37 +57,11 @@ void a4_callback_wrapper(struct ::dns_ctx *ctx, ::dns_rr_a4 *result, void *data) if (query->a6_query != NULL) { ::dns_cancel(ctx, query->a6_query); } - (*query->callback)(reinterpret_cast(&sa), 0); + (*query->callback)(static_cast(&sa), 0); delete query; } } -void a6_callback_wrapper(struct ::dns_ctx *ctx, ::dns_rr_a6 *result, void *data) { - struct sockaddr_in6 sa; - udns_query *query = static_cast(data); - // udns will free the a6_query after this callback exits - query->a6_query = NULL; - - if (result == NULL || result->dnsa6_nrr == 0) { - if (query->a4_query == NULL) { - // nothing more to do: call the callback with a failure status - (*(query->callback))(NULL, udnserror_to_gaierror(::dns_status(ctx))); - delete query; - } - // else: return and wait to see if we get an a6 response - } else { - sa.sin6_family = AF_INET6; - sa.sin6_port = 0; - sa.sin6_addr = result->dnsa6_addr[0]; - if (query->a4_query != NULL) { - ::dns_cancel(ctx, query->a4_query); - } - (*query->callback)(reinterpret_cast(&sa), 0); - delete query; - } -} - - UdnsEvent::UdnsEvent() { // reinitialize the default context, no-op // TODO don't do this here --- do it once in the manager, or in rtorrent @@ -121,7 +95,7 @@ void UdnsEvent::event_write() { void UdnsEvent::event_error() { } -struct udns_query *UdnsEvent::enqueue_resolve(const char *name, int family, resolver_callback *callback) { +struct udns_query *UdnsEvent::enqueue_resolve(const char *name, int family, async_resolver_callback *callback) { struct udns_query *query = new udns_query { NULL, NULL, callback, 0 }; if (family == AF_INET || family == AF_UNSPEC) { @@ -143,21 +117,6 @@ struct udns_query *UdnsEvent::enqueue_resolve(const char *name, int family, reso } } - if (family == AF_INET6) { - query->a6_query = ::dns_submit_a6(m_ctx, name, 0, a6_callback_wrapper, query); - if (query->a6_query == NULL) { - // it should be impossible for dns_submit_a6 to fail if dns_submit_a4 - // succeeded, but just in case, make it a hard failure: - if (::dns_status(m_ctx) == DNS_E_BADQUERY && query->a4_query == NULL) { - query->error = EAI_NONAME; - m_malformed_queries.push_back(query); - return query; - } else { - throw new internal_error("dns_submit_a6 failed"); - } - } - } - return query; } diff --git a/libtorrent/src/utils/udnsevent.h b/libtorrent/src/utils/udnsevent.h index f214814e2..42d5dce06 100644 --- a/libtorrent/src/utils/udnsevent.h +++ b/libtorrent/src/utils/udnsevent.h @@ -18,7 +18,7 @@ namespace torrent { struct udns_query { ::dns_query *a4_query; ::dns_query *a6_query; - resolver_callback *callback; + async_resolver_callback *callback; int error; }; @@ -37,7 +37,7 @@ class UdnsEvent : public Event { // wraps udns's dns_submit_a[46] functions. they and it return control immediately, // without either sending outgoing UDP packets or executing callbacks: - udns_query* enqueue_resolve(const char *name, int family, resolver_callback *callback); + udns_query* enqueue_resolve(const char *name, int family, async_resolver_callback *callback); // wraps the dns_timeouts function. it sends packets and can execute arbitrary // callbacks: void flush_resolves();