From b51727c0cd8fc37ed48a669f224df61702041097 Mon Sep 17 00:00:00 2001 From: stickz Date: Sat, 20 Jul 2024 09:23:39 -0400 Subject: [PATCH] libtorrent: Optimize UDP trackers for UDNS (#41) This commit optimizes UDP trackers with a fast path to ipv4 sockets. When using UDNS, we know the address is going to resolve to IPV4. We can skip a few checks to increase performance. --- libtorrent/src/net/socket_datagram.cc | 14 ++++++++++++-- libtorrent/src/net/socket_datagram.h | 3 +++ libtorrent/src/net/socket_fd.cc | 17 +++++++++++++++++ libtorrent/src/net/socket_fd.h | 8 ++++++++ libtorrent/src/tracker/tracker_udp.cc | 12 ++++++++++++ 5 files changed, 52 insertions(+), 2 deletions(-) diff --git a/libtorrent/src/net/socket_datagram.cc b/libtorrent/src/net/socket_datagram.cc index e7c5e1a55..7371a57b8 100644 --- a/libtorrent/src/net/socket_datagram.cc +++ b/libtorrent/src/net/socket_datagram.cc @@ -53,10 +53,9 @@ SocketDatagram::read_datagram(void* buffer, unsigned int length, rak::socket_add throw internal_error("Tried to receive buffer length 0"); int r; - socklen_t fromlen; if (sa != NULL) { - fromlen = sizeof(rak::socket_address); + socklen_t fromlen = sizeof(rak::socket_address); r = ::recvfrom(m_fileDesc, buffer, length, 0, sa->c_sockaddr(), &fromlen); } else { r = ::recv(m_fileDesc, buffer, length, 0); @@ -86,4 +85,15 @@ SocketDatagram::write_datagram(const void* buffer, unsigned int length, rak::soc return r; } +#ifdef USE_UDNS +int +SocketDatagram::write_datagram_ipv4(const void* buffer, unsigned int length, rak::socket_address* sa) { + if (length == 0) + throw internal_error("Tried to send buffer length 0"); + + return sa != NULL ? ::sendto(m_fileDesc, buffer, length, 0, sa->c_sockaddr(), sa->length()) + : ::send(m_fileDesc, buffer, length, 0); +} +#endif + } diff --git a/libtorrent/src/net/socket_datagram.h b/libtorrent/src/net/socket_datagram.h index 47649f554..a814c7a07 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); +#ifdef USE_UDNS + int write_datagram_ipv4(const void* buffer, unsigned int length, rak::socket_address* sa = NULL); +#endif }; } diff --git a/libtorrent/src/net/socket_fd.cc b/libtorrent/src/net/socket_fd.cc index f04059f6f..e54e45953 100644 --- a/libtorrent/src/net/socket_fd.cc +++ b/libtorrent/src/net/socket_fd.cc @@ -162,6 +162,14 @@ SocketFd::open_datagram() { return true; } +#ifdef USE_UDNS +bool +SocketFd::open_datagram_ipv4() { + m_ipv6_socket = false; + return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1; +} +#endif + bool SocketFd::open_local() { return (m_fd = socket(rak::socket_address::pf_local, SOCK_STREAM, 0)) != -1; @@ -198,6 +206,15 @@ SocketFd::bind(const rak::socket_address& sa) { return !::bind(m_fd, sa.c_sockaddr(), sa.length()); } +#ifdef USE_UDNS +bool +SocketFd::bind_ipv4(const rak::socket_address& sa) { + check_valid(); + + return !::bind(m_fd, sa.c_sockaddr(), sa.length()); +} +#endif + bool SocketFd::bind(const rak::socket_address& sa, unsigned int length) { check_valid(); diff --git a/libtorrent/src/net/socket_fd.h b/libtorrent/src/net/socket_fd.h index 2329b4e93..2cd7c6119 100644 --- a/libtorrent/src/net/socket_fd.h +++ b/libtorrent/src/net/socket_fd.h @@ -72,6 +72,10 @@ class SocketFd { bool open_stream(); bool open_datagram(); bool open_local(); + +#ifdef USE_UDNS + bool open_datagram_ipv4(); +#endif static bool open_socket_pair(int& fd1, int& fd2); @@ -82,6 +86,10 @@ class SocketFd { bool bind(const rak::socket_address& sa, unsigned int length); bool connect(const rak::socket_address& sa); bool getsockname(rak::socket_address* sa); + +#ifdef USE_UDNS + bool bind_ipv4(const rak::socket_address& sa); +#endif bool listen(int size); SocketFd accept(rak::socket_address* sa); diff --git a/libtorrent/src/tracker/tracker_udp.cc b/libtorrent/src/tracker/tracker_udp.cc index afe5c8ab8..fb606d412 100644 --- a/libtorrent/src/tracker/tracker_udp.cc +++ b/libtorrent/src/tracker/tracker_udp.cc @@ -136,12 +136,20 @@ 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()) +#else 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; @@ -276,7 +284,11 @@ TrackerUdp::event_write() { if (m_writeBuffer->size_end() == 0) throw internal_error("TrackerUdp::write() called but the write buffer is empty."); +#ifdef USE_UDNS + int __UNUSED s = write_datagram_ipv4(m_writeBuffer->begin(), m_writeBuffer->size_end(), &m_connectAddress); +#else int __UNUSED s = write_datagram(m_writeBuffer->begin(), m_writeBuffer->size_end(), &m_connectAddress); +#endif manager->poll()->remove_write(this); }