mirror of
https://github.com/transmission/transmission.git
synced 2025-12-20 18:38:42 +00:00
reafctor: use getaddrinfo() instead of evdns (#4094)
This commit is contained in:
@@ -11,8 +11,6 @@
|
|||||||
0A6169A80FE5C9A200C66CE6 /* bitfield.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A6169A60FE5C9A200C66CE6 /* bitfield.h */; };
|
0A6169A80FE5C9A200C66CE6 /* bitfield.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A6169A60FE5C9A200C66CE6 /* bitfield.h */; };
|
||||||
0A89346B736DBCF81F3A4850 /* torrent-metainfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0A89346B736DBCF81F3A4851 /* torrent-metainfo.cc */; };
|
0A89346B736DBCF81F3A4850 /* torrent-metainfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0A89346B736DBCF81F3A4851 /* torrent-metainfo.cc */; };
|
||||||
0A89346B736DBCF81F3A4852 /* torrent-metainfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A89346B736DBCF81F3A4853 /* torrent-metainfo.h */; };
|
0A89346B736DBCF81F3A4852 /* torrent-metainfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A89346B736DBCF81F3A4853 /* torrent-metainfo.h */; };
|
||||||
11524394C75E57E52CD9ADF0 /* dns.h in Headers */ = {isa = PBXBuildFile; fileRef = 11524394C75E57E52CD9ADF1 /* dns.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
|
||||||
11524394C75E57E52CD9ADF2 /* dns-ev.h in Headers */ = {isa = PBXBuildFile; fileRef = 11524394C75E57E52CD9ADF3 /* dns-ev.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
|
||||||
1BB44E07B1B52E28291B4E32 /* file-piece-map.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1BB44E07B1B52E28291B4E30 /* file-piece-map.cc */; };
|
1BB44E07B1B52E28291B4E32 /* file-piece-map.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1BB44E07B1B52E28291B4E30 /* file-piece-map.cc */; };
|
||||||
1BB44E07B1B52E28291B4E33 /* file-piece-map.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BB44E07B1B52E28291B4E31 /* file-piece-map.h */; };
|
1BB44E07B1B52E28291B4E33 /* file-piece-map.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BB44E07B1B52E28291B4E31 /* file-piece-map.h */; };
|
||||||
2856E0656A49F2665D69E760 /* benc.h in Headers */ = {isa = PBXBuildFile; fileRef = 2856E0656A49F2665D69E761 /* benc.h */; };
|
2856E0656A49F2665D69E760 /* benc.h in Headers */ = {isa = PBXBuildFile; fileRef = 2856E0656A49F2665D69E761 /* benc.h */; };
|
||||||
@@ -602,8 +600,6 @@
|
|||||||
0A89346B736DBCF81F3A4851 /* torrent-metainfo.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "torrent-metainfo.cc"; sourceTree = "<group>"; };
|
0A89346B736DBCF81F3A4851 /* torrent-metainfo.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "torrent-metainfo.cc"; sourceTree = "<group>"; };
|
||||||
0A89346B736DBCF81F3A4853 /* torrent-metainfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "torrent-metainfo.h"; sourceTree = "<group>"; };
|
0A89346B736DBCF81F3A4853 /* torrent-metainfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "torrent-metainfo.h"; sourceTree = "<group>"; };
|
||||||
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
||||||
11524394C75E57E52CD9ADF1 /* dns.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = dns.h; sourceTree = "<group>"; };
|
|
||||||
11524394C75E57E52CD9ADF3 /* dns-ev.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = "dns-ev.h"; sourceTree = "<group>"; };
|
|
||||||
13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
|
13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
|
||||||
1BB44E07B1B52E28291B4E30 /* file-piece-map.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "file-piece-map.cc"; sourceTree = "<group>"; };
|
1BB44E07B1B52E28291B4E30 /* file-piece-map.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "file-piece-map.cc"; sourceTree = "<group>"; };
|
||||||
1BB44E07B1B52E28291B4E31 /* file-piece-map.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "file-piece-map.h"; sourceTree = "<group>"; };
|
1BB44E07B1B52E28291B4E31 /* file-piece-map.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "file-piece-map.h"; sourceTree = "<group>"; };
|
||||||
@@ -1706,8 +1702,6 @@
|
|||||||
C11DEA151FCD31C0009E22B9 /* subprocess.h */,
|
C11DEA151FCD31C0009E22B9 /* subprocess.h */,
|
||||||
E975121263DD973CAF4AEBA5 /* timer-ev.cc */,
|
E975121263DD973CAF4AEBA5 /* timer-ev.cc */,
|
||||||
E975121263DD973CAF4AEBA3 /* timer-ev.h */,
|
E975121263DD973CAF4AEBA3 /* timer-ev.h */,
|
||||||
11524394C75E57E52CD9ADF1 /* dns.h */,
|
|
||||||
11524394C75E57E52CD9ADF3 /* dns-ev.h */,
|
|
||||||
E975121263DD973CAF4AEBA1 /* timer.h */,
|
E975121263DD973CAF4AEBA1 /* timer.h */,
|
||||||
A20152790D1C26EB0081714F /* torrent-ctor.cc */,
|
A20152790D1C26EB0081714F /* torrent-ctor.cc */,
|
||||||
A47A7C87B8B57BE50DF0D411 /* torrent-files.cc */,
|
A47A7C87B8B57BE50DF0D411 /* torrent-files.cc */,
|
||||||
@@ -2220,8 +2214,6 @@
|
|||||||
2856E0656A49F2665D69E760 /* benc.h in Headers */,
|
2856E0656A49F2665D69E760 /* benc.h in Headers */,
|
||||||
E975121263DD973CAF4AEBA0 /* timer.h in Headers */,
|
E975121263DD973CAF4AEBA0 /* timer.h in Headers */,
|
||||||
E975121263DD973CAF4AEBA2 /* timer-ev.h in Headers */,
|
E975121263DD973CAF4AEBA2 /* timer-ev.h in Headers */,
|
||||||
11524394C75E57E52CD9ADF0 /* dns.h in Headers */,
|
|
||||||
11524394C75E57E52CD9ADF2 /* dns-ev.h in Headers */,
|
|
||||||
C1077A4F183EB29600634C22 /* error.h in Headers */,
|
C1077A4F183EB29600634C22 /* error.h in Headers */,
|
||||||
A2679295130E00A000CB7464 /* tr-utp.h in Headers */,
|
A2679295130E00A000CB7464 /* tr-utp.h in Headers */,
|
||||||
A263C6B1F6718E2486DB20E0 /* tr-buffer.h in Headers */,
|
A263C6B1F6718E2486DB20E0 /* tr-buffer.h in Headers */,
|
||||||
|
|||||||
@@ -136,8 +136,6 @@ endif()
|
|||||||
|
|
||||||
set(${PROJECT_NAME}_PUBLIC_HEADERS
|
set(${PROJECT_NAME}_PUBLIC_HEADERS
|
||||||
${PROJECT_BINARY_DIR}/version.h
|
${PROJECT_BINARY_DIR}/version.h
|
||||||
dns-ev.h
|
|
||||||
dns.h
|
|
||||||
error-types.h
|
error-types.h
|
||||||
error.h
|
error.h
|
||||||
file.h
|
file.h
|
||||||
|
|||||||
@@ -5,13 +5,17 @@
|
|||||||
|
|
||||||
#include <algorithm> // for std::find_if()
|
#include <algorithm> // for std::find_if()
|
||||||
#include <cerrno> // for errno, EAFNOSUPPORT
|
#include <cerrno> // for errno, EAFNOSUPPORT
|
||||||
#include <cstring> // for memset()
|
#include <cstring> // for memcpy()
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
@@ -23,6 +27,7 @@
|
|||||||
#include "announcer-common.h"
|
#include "announcer-common.h"
|
||||||
#include "crypto-utils.h" /* tr_rand_buffer() */
|
#include "crypto-utils.h" /* tr_rand_buffer() */
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "error.h"
|
||||||
#include "peer-io.h"
|
#include "peer-io.h"
|
||||||
#include "peer-mgr.h" // for tr_pex::fromCompact4()
|
#include "peer-mgr.h" // for tr_pex::fromCompact4()
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
@@ -31,6 +36,11 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "web-utils.h"
|
#include "web-utils.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#undef gai_strerror
|
||||||
|
#define gai_strerror gai_strerrorA
|
||||||
|
#endif
|
||||||
|
|
||||||
#define logwarn(interned, msg) tr_logAddWarn(msg, (interned).sv())
|
#define logwarn(interned, msg) tr_logAddWarn(msg, (interned).sv())
|
||||||
#define logdbg(interned, msg) tr_logAddDebug(msg, (interned).sv())
|
#define logdbg(interned, msg) tr_logAddDebug(msg, (interned).sv())
|
||||||
#define logtrace(interned, msg) tr_logAddTrace(msg, (interned).sv())
|
#define logtrace(interned, msg) tr_logAddTrace(msg, (interned).sv())
|
||||||
@@ -331,9 +341,19 @@ struct tau_tracker
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tau_tracker(tau_tracker&&) = delete;
|
||||||
|
tau_tracker(tau_tracker const&) = delete;
|
||||||
|
tau_tracker& operator=(tau_tracker&&) = delete;
|
||||||
|
tau_tracker& operator=(tau_tracker const&) = delete;
|
||||||
|
|
||||||
|
~tau_tracker()
|
||||||
|
{
|
||||||
|
tr_error_clear(&addr_error_);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto isIdle() const noexcept
|
[[nodiscard]] auto isIdle() const noexcept
|
||||||
{
|
{
|
||||||
return std::empty(announces) && std::empty(scrapes) && (dns_request_ == 0U);
|
return std::empty(announces) && std::empty(scrapes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void failAll(bool did_connect, bool did_timeout, std::string_view errmsg)
|
void failAll(bool did_connect, bool did_timeout, std::string_view errmsg)
|
||||||
@@ -374,7 +394,7 @@ struct tau_tracker
|
|||||||
tr_interned_string const host;
|
tr_interned_string const host;
|
||||||
tr_port const port;
|
tr_port const port;
|
||||||
|
|
||||||
libtransmission::Dns::Tag dns_request_ = {};
|
tr_error* addr_error_ = nullptr;
|
||||||
std::optional<std::pair<sockaddr_storage, socklen_t>> addr_;
|
std::optional<std::pair<sockaddr_storage, socklen_t>> addr_;
|
||||||
time_t addr_expires_at_ = 0;
|
time_t addr_expires_at_ = 0;
|
||||||
|
|
||||||
@@ -391,30 +411,43 @@ struct tau_tracker
|
|||||||
std::list<tau_scrape_request> scrapes;
|
std::list<tau_scrape_request> scrapes;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void tau_tracker_upkeep(struct tau_tracker* /*tracker*/);
|
static std::optional<std::pair<sockaddr_storage, socklen_t>> host2sockaddr(
|
||||||
|
std::string_view host,
|
||||||
static void tau_tracker_on_dns(tau_tracker* const tracker, sockaddr const* sa, socklen_t salen, time_t expires_at)
|
tr_port port,
|
||||||
|
tr_error** error)
|
||||||
{
|
{
|
||||||
tracker->dns_request_ = {};
|
auto const szhost = tr_urlbuf{ host };
|
||||||
|
|
||||||
if (sa == nullptr)
|
auto szport = std::array<char, 16>{};
|
||||||
|
*fmt::format_to(std::data(szport), FMT_STRING("{:d}"), port.host()) = '\0';
|
||||||
|
|
||||||
|
auto hints = addrinfo{};
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_protocol = IPPROTO_UDP;
|
||||||
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
|
|
||||||
|
addrinfo* info = nullptr;
|
||||||
|
if (int const rc = getaddrinfo(szhost, std::data(szport), &hints, &info); rc != 0)
|
||||||
{
|
{
|
||||||
auto const errmsg = fmt::format(_("Couldn't find address of tracker '{host}'"), fmt::arg("host", tracker->host));
|
tr_logAddWarn(fmt::format(
|
||||||
logwarn(tracker->key, errmsg);
|
_("Couldn't look up '{address}:{port}': {error} ({error_code})"),
|
||||||
tracker->failAll(false, false, errmsg.c_str());
|
fmt::arg("address", host),
|
||||||
tracker->addr_expires_at_ = tr_time() + tau_tracker::DnsRetryIntervalSecs;
|
fmt::arg("port", port.host()),
|
||||||
|
fmt::arg("error", gai_strerror(rc)),
|
||||||
|
fmt::arg("error_code", rc)));
|
||||||
|
tr_error_set(error, rc, gai_strerror(rc));
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
logdbg(tracker->key, "DNS lookup succeeded");
|
|
||||||
auto ss = sockaddr_storage{};
|
auto ss = sockaddr_storage{};
|
||||||
memcpy(&ss, sa, salen);
|
auto const len = info->ai_addrlen;
|
||||||
tracker->addr_.emplace(ss, salen);
|
memcpy(&ss, info->ai_addr, len);
|
||||||
tracker->addr_expires_at_ = expires_at;
|
freeaddrinfo(info);
|
||||||
tau_tracker_upkeep(tracker);
|
return std::make_pair(ss, len);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tau_tracker_upkeep(struct tau_tracker* /*tracker*/);
|
||||||
|
|
||||||
static void tau_tracker_send_request(struct tau_tracker* tracker, void const* payload, size_t payload_len)
|
static void tau_tracker_send_request(struct tau_tracker* tracker, void const* payload, size_t payload_len)
|
||||||
{
|
{
|
||||||
logdbg(tracker->key, fmt::format("sending request w/connection id {}", tracker->connection_id));
|
logdbg(tracker->key, fmt::format("sending request w/connection id {}", tracker->connection_id));
|
||||||
@@ -459,7 +492,6 @@ static void tau_tracker_send_requests(tau_tracker* tracker, std::list<T>& reqs)
|
|||||||
|
|
||||||
static void tau_tracker_send_reqs(tau_tracker* tracker)
|
static void tau_tracker_send_reqs(tau_tracker* tracker)
|
||||||
{
|
{
|
||||||
TR_ASSERT(!tracker->dns_request_);
|
|
||||||
TR_ASSERT(tracker->addr_);
|
TR_ASSERT(tracker->addr_);
|
||||||
TR_ASSERT(tracker->connecting_at == 0);
|
TR_ASSERT(tracker->connecting_at == 0);
|
||||||
TR_ASSERT(tracker->connection_expiration_time > tr_time());
|
TR_ASSERT(tracker->connection_expiration_time > tr_time());
|
||||||
@@ -562,21 +594,21 @@ static void tau_tracker_upkeep_ex(struct tau_tracker* tracker, bool timeout_reqs
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we don't have an address yet, try & get one now. */
|
// if we don't have an address yet, try & get one now
|
||||||
if (!closing && !tracker->addr_ && (tracker->dns_request_ == 0U))
|
if (!closing && !tracker->addr_)
|
||||||
{
|
{
|
||||||
auto hints = libtransmission::Dns::Hints{};
|
if (tracker->addr_expires_at_ <= now)
|
||||||
hints.ai_family = AF_UNSPEC;
|
{
|
||||||
hints.ai_socktype = SOCK_DGRAM;
|
tr_error_clear(&tracker->addr_error_);
|
||||||
hints.ai_protocol = IPPROTO_UDP;
|
tracker->addr_ = host2sockaddr(tracker->host, tracker->port, &tracker->addr_error_);
|
||||||
logtrace(tracker->host, "Trying a new DNS lookup");
|
tracker->addr_expires_at_ = now + tau_tracker::DnsRetryIntervalSecs;
|
||||||
tracker->dns_request_ = tracker->mediator_.dns().lookup(
|
}
|
||||||
tracker->host.sv(),
|
if (tracker->addr_error_ != nullptr)
|
||||||
[tracker](sockaddr const* sa, socklen_t len, time_t expires_at)
|
{
|
||||||
{ tau_tracker_on_dns(tracker, sa, len, expires_at); },
|
tracker->failAll(false, false, tracker->addr_error_->message);
|
||||||
hints);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logtrace(
|
logtrace(
|
||||||
tracker->key,
|
tracker->key,
|
||||||
@@ -684,12 +716,6 @@ public:
|
|||||||
|
|
||||||
for (auto& tracker : trackers_)
|
for (auto& tracker : trackers_)
|
||||||
{
|
{
|
||||||
// if there's a pending DNS request, cancel it
|
|
||||||
if (tracker.dns_request_ != 0U)
|
|
||||||
{
|
|
||||||
mediator_.dns().cancel(tracker.dns_request_);
|
|
||||||
}
|
|
||||||
|
|
||||||
tracker.close_at = now + 3;
|
tracker.close_at = now + 3;
|
||||||
tau_tracker_upkeep(&tracker);
|
tau_tracker_upkeep(&tracker);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -301,7 +301,6 @@ public:
|
|||||||
public:
|
public:
|
||||||
virtual ~Mediator() noexcept = default;
|
virtual ~Mediator() noexcept = default;
|
||||||
virtual void sendto(void const* buf, size_t buflen, sockaddr const* addr, socklen_t addrlen) = 0;
|
virtual void sendto(void const* buf, size_t buflen, sockaddr const* addr, socklen_t addrlen) = 0;
|
||||||
[[nodiscard]] virtual libtransmission::Dns& dns() = 0;
|
|
||||||
[[nodiscard]] virtual std::optional<tr_address> announceIP() const = 0;
|
[[nodiscard]] virtual std::optional<tr_address> announceIP() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,210 +0,0 @@
|
|||||||
// This file Copyright 2022 Mnemosyne LLC.
|
|
||||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
|
||||||
// or any future license endorsed by Mnemosyne LLC.
|
|
||||||
// License text can be found in the licenses/ folder.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#ifndef __TRANSMISSION__
|
|
||||||
#error only libtransmission should #include this header.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <cstring> // for std::memcpy()
|
|
||||||
#include <ctime>
|
|
||||||
#include <list>
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include <event2/dns.h>
|
|
||||||
#include <event2/event.h>
|
|
||||||
|
|
||||||
#include "dns.h"
|
|
||||||
#include "utils.h" // for tr_strlower()
|
|
||||||
|
|
||||||
namespace libtransmission
|
|
||||||
{
|
|
||||||
|
|
||||||
class EvDns final : public Dns
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
using Key = std::pair<std::string, Hints>;
|
|
||||||
|
|
||||||
struct CacheEntry
|
|
||||||
{
|
|
||||||
sockaddr_storage ss_ = {};
|
|
||||||
socklen_t sslen_ = {};
|
|
||||||
time_t expires_at_ = {};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CallbackArg
|
|
||||||
{
|
|
||||||
Key key;
|
|
||||||
EvDns* self;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Request
|
|
||||||
{
|
|
||||||
evdns_getaddrinfo_request* request;
|
|
||||||
|
|
||||||
struct CallbackInfo
|
|
||||||
{
|
|
||||||
CallbackInfo(Tag tag, Callback callback)
|
|
||||||
: tag_{ tag }
|
|
||||||
, callback_{ std::move(callback) }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Tag tag_;
|
|
||||||
Callback callback_;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::list<CallbackInfo> callbacks;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
using TimeFunc = time_t (*)();
|
|
||||||
|
|
||||||
EvDns(struct event_base* event_base, TimeFunc time_func)
|
|
||||||
: time_func_{ time_func }
|
|
||||||
, evdns_base_{ evdns_base_new(event_base, EVDNS_BASE_INITIALIZE_NAMESERVERS),
|
|
||||||
[](evdns_base* dns)
|
|
||||||
{
|
|
||||||
// if zero, active requests will be aborted
|
|
||||||
evdns_base_free(dns, 0);
|
|
||||||
} }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~EvDns() override
|
|
||||||
{
|
|
||||||
for (auto& [key, request] : requests_)
|
|
||||||
{
|
|
||||||
evdns_getaddrinfo_cancel(request.request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::pair<sockaddr const*, socklen_t>> cached(std::string_view address, Hints hints = {}) const override
|
|
||||||
{
|
|
||||||
if (auto const* entry = cached(makeKey(address, hints)); entry != nullptr)
|
|
||||||
{
|
|
||||||
return std::make_pair(reinterpret_cast<sockaddr const*>(&entry->ss_), entry->sslen_);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Tag lookup(std::string_view address, Callback&& callback, Hints hints = {}) override
|
|
||||||
{
|
|
||||||
auto const key = makeKey(address, hints);
|
|
||||||
|
|
||||||
if (auto const* entry = cached(key); entry)
|
|
||||||
{
|
|
||||||
callback(reinterpret_cast<sockaddr const*>(&entry->ss_), entry->sslen_, entry->expires_at_);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& request = requests_[key];
|
|
||||||
auto const tag = next_tag_;
|
|
||||||
++next_tag_;
|
|
||||||
request.callbacks.emplace_back(tag, std::move(callback));
|
|
||||||
if (request.request == nullptr)
|
|
||||||
{
|
|
||||||
auto evhints = evutil_addrinfo{};
|
|
||||||
evhints.ai_family = hints.ai_family;
|
|
||||||
evhints.ai_socktype = hints.ai_socktype;
|
|
||||||
evhints.ai_protocol = hints.ai_protocol;
|
|
||||||
void* const arg = new CallbackArg{ key, this };
|
|
||||||
request.request = evdns_getaddrinfo(evdns_base_.get(), key.first.c_str(), nullptr, &evhints, evcallback, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cancel(Tag tag) override
|
|
||||||
{
|
|
||||||
for (auto& [key, request] : requests_)
|
|
||||||
{
|
|
||||||
for (auto iter = std::begin(request.callbacks), end = std::end(request.callbacks); iter != end; ++iter)
|
|
||||||
{
|
|
||||||
if (iter->tag_ != tag)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
iter->callback_(nullptr, 0, 0);
|
|
||||||
|
|
||||||
request.callbacks.erase(iter);
|
|
||||||
|
|
||||||
// if this was the last pending request for `key`, cancel the evdns request
|
|
||||||
if (std::empty(request.callbacks))
|
|
||||||
{
|
|
||||||
evdns_getaddrinfo_cancel(request.request);
|
|
||||||
requests_.erase(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
[[nodiscard]] static Key makeKey(std::string_view address, Hints hints)
|
|
||||||
{
|
|
||||||
return Key{ tr_strlower(address), hints };
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] CacheEntry const* cached(Key const& key) const
|
|
||||||
{
|
|
||||||
if (auto iter = cache_.find(key); iter != std::end(cache_))
|
|
||||||
{
|
|
||||||
auto const& entry = iter->second;
|
|
||||||
|
|
||||||
if (auto const now = time_func_(); entry.expires_at_ > now)
|
|
||||||
{
|
|
||||||
return &entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
cache_.erase(iter); // expired
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void evcallback(int /*result*/, struct evutil_addrinfo* res, void* varg)
|
|
||||||
{
|
|
||||||
auto* const arg = static_cast<CallbackArg*>(varg);
|
|
||||||
auto [key, self] = *arg;
|
|
||||||
delete arg;
|
|
||||||
|
|
||||||
auto& cache_entry = self->cache_[key];
|
|
||||||
|
|
||||||
if (res != nullptr)
|
|
||||||
{
|
|
||||||
cache_entry.expires_at_ = self->time_func_() + CacheTtlSecs;
|
|
||||||
cache_entry.sslen_ = res->ai_addrlen;
|
|
||||||
std::memcpy(&cache_entry.ss_, res->ai_addr, res->ai_addrlen);
|
|
||||||
evutil_freeaddrinfo(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto request_entry = self->requests_.extract(key); request_entry)
|
|
||||||
{
|
|
||||||
for (auto& callback : request_entry.mapped().callbacks)
|
|
||||||
{
|
|
||||||
callback.callback_(
|
|
||||||
reinterpret_cast<sockaddr const*>(&cache_entry.ss_),
|
|
||||||
cache_entry.sslen_,
|
|
||||||
cache_entry.expires_at_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TimeFunc const time_func_;
|
|
||||||
static time_t constexpr CacheTtlSecs = 3600U;
|
|
||||||
std::unique_ptr<evdns_base, void (*)(evdns_base*)> const evdns_base_;
|
|
||||||
mutable std::map<Key, CacheEntry> cache_;
|
|
||||||
std::map<Key, Request> requests_;
|
|
||||||
unsigned int next_tag_ = 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace libtransmission
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
// This file Copyright 2022 Mnemosyne LLC.
|
|
||||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
|
||||||
// or any future license endorsed by Mnemosyne LLC.
|
|
||||||
// License text can be found in the licenses/ folder.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <string_view>
|
|
||||||
|
|
||||||
#include "transmission.h"
|
|
||||||
|
|
||||||
#include "net.h"
|
|
||||||
|
|
||||||
namespace libtransmission
|
|
||||||
{
|
|
||||||
|
|
||||||
class Dns
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~Dns() = default;
|
|
||||||
|
|
||||||
using Callback = std::function<void(struct sockaddr const*, socklen_t salen, time_t expires_at)>;
|
|
||||||
using Tag = unsigned int;
|
|
||||||
|
|
||||||
class Hints
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Hints()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int ai_family = AF_UNSPEC;
|
|
||||||
int ai_socktype = SOCK_DGRAM;
|
|
||||||
int ai_protocol = IPPROTO_UDP;
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr int compare(Hints const& that) const noexcept // <=>
|
|
||||||
{
|
|
||||||
if (ai_family != that.ai_family)
|
|
||||||
{
|
|
||||||
return ai_family < that.ai_family ? -1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ai_socktype != that.ai_socktype)
|
|
||||||
{
|
|
||||||
return ai_socktype < that.ai_socktype ? -1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ai_protocol != that.ai_protocol)
|
|
||||||
{
|
|
||||||
return ai_protocol < that.ai_protocol ? -1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr bool operator<(Hints const& that) const noexcept
|
|
||||||
{
|
|
||||||
return compare(that) < 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
[[nodiscard]] virtual std::optional<std::pair<struct sockaddr const*, socklen_t>> cached(
|
|
||||||
std::string_view address,
|
|
||||||
Hints hints = {}) const = 0;
|
|
||||||
|
|
||||||
virtual Tag lookup(std::string_view address, Callback&& callback, Hints hints = {}) = 0;
|
|
||||||
|
|
||||||
virtual void cancel(Tag) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace libtransmission
|
|
||||||
@@ -25,7 +25,6 @@
|
|||||||
#include <sys/stat.h> /* umask() */
|
#include <sys/stat.h> /* umask() */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <event2/dns.h>
|
|
||||||
#include <event2/event.h>
|
#include <event2/event.h>
|
||||||
|
|
||||||
#include <fmt/chrono.h>
|
#include <fmt/chrono.h>
|
||||||
@@ -39,7 +38,6 @@
|
|||||||
#include "blocklist.h"
|
#include "blocklist.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "crypto-utils.h"
|
#include "crypto-utils.h"
|
||||||
#include "dns-ev.h"
|
|
||||||
#include "error-types.h"
|
#include "error-types.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
@@ -2237,7 +2235,6 @@ tr_session::tr_session(std::string_view config_dir, tr_variant* settings_dict)
|
|||||||
, blocklist_dir_{ makeBlocklistDir(config_dir) }
|
, blocklist_dir_{ makeBlocklistDir(config_dir) }
|
||||||
, event_base_{ makeEventBase() }
|
, event_base_{ makeEventBase() }
|
||||||
, timer_maker_{ std::make_unique<libtransmission::EvTimerMaker>(eventBase()) }
|
, timer_maker_{ std::make_unique<libtransmission::EvTimerMaker>(eventBase()) }
|
||||||
, dns_{ std::make_unique<libtransmission::EvDns>(eventBase(), tr_time) }
|
|
||||||
, settings_{ settings_dict }
|
, settings_{ settings_dict }
|
||||||
, session_id_{ tr_time }
|
, session_id_{ tr_time }
|
||||||
, peer_mgr_{ tr_peerMgrNew(this), tr_peerMgrFree }
|
, peer_mgr_{ tr_peerMgrNew(this), tr_peerMgrFree }
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
#include "bandwidth.h"
|
#include "bandwidth.h"
|
||||||
#include "bitfield.h"
|
#include "bitfield.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "dns.h"
|
|
||||||
#include "interned-string.h"
|
#include "interned-string.h"
|
||||||
#include "net.h" // tr_socket_t
|
#include "net.h" // tr_socket_t
|
||||||
#include "open-files.h"
|
#include "open-files.h"
|
||||||
@@ -140,11 +139,6 @@ private:
|
|||||||
return tr_address::fromString(session_.announceIP());
|
return tr_address::fromString(session_.announceIP());
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] libtransmission::Dns& dns() override
|
|
||||||
{
|
|
||||||
return *session_.dns_.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
tr_session& session_;
|
tr_session& session_;
|
||||||
};
|
};
|
||||||
@@ -987,9 +981,6 @@ private:
|
|||||||
// depends-on: event_base_
|
// depends-on: event_base_
|
||||||
std::unique_ptr<libtransmission::TimerMaker> const timer_maker_;
|
std::unique_ptr<libtransmission::TimerMaker> const timer_maker_;
|
||||||
|
|
||||||
// depends-on: event_base_
|
|
||||||
std::unique_ptr<libtransmission::Dns> const dns_;
|
|
||||||
|
|
||||||
/// static fields
|
/// static fields
|
||||||
|
|
||||||
static std::recursive_mutex session_mutex_;
|
static std::recursive_mutex session_mutex_;
|
||||||
@@ -1092,7 +1083,7 @@ private:
|
|||||||
// depends-on: lpd_mediator_
|
// depends-on: lpd_mediator_
|
||||||
std::unique_ptr<tr_lpd> lpd_;
|
std::unique_ptr<tr_lpd> lpd_;
|
||||||
|
|
||||||
// depends-on: dns_, udp_core_
|
// depends-on: udp_core_
|
||||||
AnnouncerUdpMediator announcer_udp_mediator_{ *this };
|
AnnouncerUdpMediator announcer_udp_mediator_{ *this };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -2348,7 +2348,7 @@ void tr_torrentSetQueuePosition(tr_torrent* tor, size_t queue_position)
|
|||||||
size_t current = 0;
|
size_t current = 0;
|
||||||
auto const old_pos = tor->queuePosition;
|
auto const old_pos = tor->queuePosition;
|
||||||
|
|
||||||
tor->queuePosition = -1;
|
tor->queuePosition = static_cast<size_t>(-1);
|
||||||
|
|
||||||
for (auto* const walk : tor->session->torrents())
|
for (auto* const walk : tor->session->torrents())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ add_executable(libtransmission-test
|
|||||||
crypto-test-ref.h
|
crypto-test-ref.h
|
||||||
crypto-test.cc
|
crypto-test.cc
|
||||||
error-test.cc
|
error-test.cc
|
||||||
dns-test.cc
|
|
||||||
file-piece-map-test.cc
|
file-piece-map-test.cc
|
||||||
file-test.cc
|
file-test.cc
|
||||||
getopt-test.cc
|
getopt-test.cc
|
||||||
|
|||||||
@@ -14,9 +14,9 @@
|
|||||||
|
|
||||||
#include "announcer.h"
|
#include "announcer.h"
|
||||||
#include "crypto-utils.h"
|
#include "crypto-utils.h"
|
||||||
#include "dns.h"
|
|
||||||
#include "peer-mgr.h" // for tr_pex
|
#include "peer-mgr.h" // for tr_pex
|
||||||
#include "tr-buffer.h"
|
#include "tr-buffer.h"
|
||||||
|
#include "utils.h" // for tr_net_init()
|
||||||
|
|
||||||
#include "test-fixtures.h"
|
#include "test-fixtures.h"
|
||||||
|
|
||||||
@@ -28,45 +28,15 @@ private:
|
|||||||
void SetUp() override
|
void SetUp() override
|
||||||
{
|
{
|
||||||
::testing::Test::SetUp();
|
::testing::Test::SetUp();
|
||||||
|
|
||||||
|
tr_net_init();
|
||||||
tr_timeUpdate(time(nullptr));
|
tr_timeUpdate(time(nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
class MockDns final : public libtransmission::Dns
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
~MockDns() override = default;
|
|
||||||
|
|
||||||
[[nodiscard]] std::optional<std::pair<struct sockaddr const*, socklen_t>> cached(
|
|
||||||
std::string_view /*address*/,
|
|
||||||
Hints /*hints*/ = {}) const override
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Tag lookup(std::string_view address, Callback&& callback, Hints /*hints*/) override
|
|
||||||
{
|
|
||||||
auto const addr = tr_address::fromString(address); // mock has no actual DNS, just parsing e.g. inet_pton
|
|
||||||
auto [ss, sslen] = addr->toSockaddr(Port);
|
|
||||||
callback(reinterpret_cast<sockaddr const*>(&ss), sslen, tr_time() + 3600); // 1hr ttl
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void cancel(Tag /*tag*/) override
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static auto constexpr Port = tr_port::fromHost(443);
|
|
||||||
};
|
|
||||||
|
|
||||||
class MockMediator final : public tr_announcer_udp::Mediator
|
class MockMediator final : public tr_announcer_udp::Mediator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MockMediator()
|
|
||||||
: event_base_{ event_base_new(), event_base_free }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void sendto(void const* buf, size_t buflen, sockaddr const* sa, socklen_t salen) override
|
void sendto(void const* buf, size_t buflen, sockaddr const* sa, socklen_t salen) override
|
||||||
{
|
{
|
||||||
auto target = tr_address::fromSockaddr(sa);
|
auto target = tr_address::fromSockaddr(sa);
|
||||||
@@ -74,16 +44,6 @@ protected:
|
|||||||
sent_.emplace_back(static_cast<char const*>(buf), buflen, sa, salen);
|
sent_.emplace_back(static_cast<char const*>(buf), buflen, sa, salen);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto* eventBase()
|
|
||||||
{
|
|
||||||
return event_base_.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] libtransmission::Dns& dns() override
|
|
||||||
{
|
|
||||||
return dns_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] std::optional<tr_address> announceIP() const override
|
[[nodiscard]] std::optional<tr_address> announceIP() const override
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
@@ -106,10 +66,6 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::deque<Sent> sent_;
|
std::deque<Sent> sent_;
|
||||||
|
|
||||||
std::unique_ptr<event_base, void (*)(event_base*)> const event_base_;
|
|
||||||
|
|
||||||
MockDns dns_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void expectEqual(tr_scrape_response const& expected, tr_scrape_response const& actual)
|
static void expectEqual(tr_scrape_response const& expected, tr_scrape_response const& actual)
|
||||||
@@ -202,7 +158,7 @@ protected:
|
|||||||
[[nodiscard]] static auto waitForAnnouncerToSendMessage(MockMediator& mediator)
|
[[nodiscard]] static auto waitForAnnouncerToSendMessage(MockMediator& mediator)
|
||||||
{
|
{
|
||||||
EXPECT_FALSE(std::empty(mediator.sent_));
|
EXPECT_FALSE(std::empty(mediator.sent_));
|
||||||
libtransmission::test::waitFor(mediator.eventBase(), [&mediator]() { return !std::empty(mediator.sent_); });
|
libtransmission::test::waitFor([&mediator]() { return !std::empty(mediator.sent_); }, 5s);
|
||||||
auto buf = libtransmission::Buffer(mediator.sent_.back().buf_);
|
auto buf = libtransmission::Buffer(mediator.sent_.back().buf_);
|
||||||
mediator.sent_.pop_back();
|
mediator.sent_.pop_back();
|
||||||
return buf;
|
return buf;
|
||||||
@@ -265,8 +221,8 @@ protected:
|
|||||||
EXPECT_EQ(expected.up, actual.uploaded);
|
EXPECT_EQ(expected.up, actual.uploaded);
|
||||||
// EXPECT_EQ(foo, actual.event); ; // 0: none; 1: completed; 2: started; 3: stopped // FIXME
|
// EXPECT_EQ(foo, actual.event); ; // 0: none; 1: completed; 2: started; 3: stopped // FIXME
|
||||||
// EXPECT_EQ(foo, actual.ip_address); // FIXME
|
// EXPECT_EQ(foo, actual.ip_address); // FIXME
|
||||||
EXPECT_EQ(expected.key, actual.key);
|
EXPECT_EQ(expected.key, static_cast<decltype(expected.key)>(actual.key));
|
||||||
EXPECT_EQ(expected.numwant, actual.num_want);
|
EXPECT_EQ(expected.numwant, static_cast<decltype(expected.numwant)>(actual.num_want));
|
||||||
EXPECT_EQ(expected.port.host(), actual.port);
|
EXPECT_EQ(expected.port.host(), actual.port);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,7 +368,7 @@ TEST_F(AnnouncerUdpTest, canDestructCleanlyEvenWhenBusy)
|
|||||||
// Inspect that request for validity.
|
// Inspect that request for validity.
|
||||||
auto sent = waitForAnnouncerToSendMessage(mediator);
|
auto sent = waitForAnnouncerToSendMessage(mediator);
|
||||||
auto const connect_transaction_id = parseConnectionRequest(sent);
|
auto const connect_transaction_id = parseConnectionRequest(sent);
|
||||||
EXPECT_NE(0, connect_transaction_id);
|
EXPECT_NE(0U, connect_transaction_id);
|
||||||
|
|
||||||
// now just end the test before responding to the request.
|
// now just end the test before responding to the request.
|
||||||
// the announcer and mediator will go out-of-scope & be destroyed.
|
// the announcer and mediator will go out-of-scope & be destroyed.
|
||||||
|
|||||||
@@ -1,175 +0,0 @@
|
|||||||
// This file Copyright (C) 2022 Mnemosyne LLC.
|
|
||||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
|
||||||
// or any future license endorsed by Mnemosyne LLC.
|
|
||||||
// License text can be found in the licenses/ folder.
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <event2/event.h>
|
|
||||||
|
|
||||||
#include "transmission.h"
|
|
||||||
|
|
||||||
#include "dns-ev.h"
|
|
||||||
#include "dns.h"
|
|
||||||
#include "trevent.h" // for tr_evthread_init();
|
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
|
||||||
#include "test-fixtures.h"
|
|
||||||
|
|
||||||
using namespace std::literals;
|
|
||||||
|
|
||||||
namespace libtransmission::test
|
|
||||||
{
|
|
||||||
|
|
||||||
class EvDnsTest : public ::testing::Test
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
void SetUp() override
|
|
||||||
{
|
|
||||||
::testing::Test::SetUp();
|
|
||||||
|
|
||||||
tr_evthread_init();
|
|
||||||
event_base_ = event_base_new();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TearDown() override
|
|
||||||
{
|
|
||||||
event_base_free(event_base_);
|
|
||||||
event_base_ = nullptr;
|
|
||||||
|
|
||||||
::testing::Test::TearDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct event_base* event_base_ = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(EvDnsTest, canLookup)
|
|
||||||
{
|
|
||||||
auto dns = EvDns{ event_base_, tr_time };
|
|
||||||
auto done = false;
|
|
||||||
|
|
||||||
dns.lookup(
|
|
||||||
"example.com",
|
|
||||||
[&done](struct sockaddr const* ai, socklen_t ailen, time_t expires_at)
|
|
||||||
{
|
|
||||||
EXPECT_NE(nullptr, ai);
|
|
||||||
EXPECT_GT(ailen, 0);
|
|
||||||
EXPECT_GT(expires_at, tr_time());
|
|
||||||
done = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
waitFor(event_base_, [&done]() { return done; });
|
|
||||||
EXPECT_TRUE(done);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(EvDnsTest, canRequestWhilePending)
|
|
||||||
{
|
|
||||||
auto dns = EvDns{ event_base_, tr_time };
|
|
||||||
auto n_done = size_t{ 0 };
|
|
||||||
|
|
||||||
dns.lookup(
|
|
||||||
"example.com",
|
|
||||||
[&n_done](struct sockaddr const* ai, socklen_t ailen, time_t expires_at)
|
|
||||||
{
|
|
||||||
EXPECT_NE(nullptr, ai);
|
|
||||||
EXPECT_GT(ailen, 0);
|
|
||||||
EXPECT_GT(expires_at, tr_time());
|
|
||||||
++n_done;
|
|
||||||
});
|
|
||||||
|
|
||||||
dns.lookup(
|
|
||||||
"example.com",
|
|
||||||
[&n_done](struct sockaddr const* ai, socklen_t ailen, time_t expires_at)
|
|
||||||
{
|
|
||||||
EXPECT_NE(nullptr, ai);
|
|
||||||
EXPECT_GT(ailen, 0);
|
|
||||||
EXPECT_GT(expires_at, tr_time());
|
|
||||||
++n_done;
|
|
||||||
});
|
|
||||||
|
|
||||||
// wait for both callbacks to be called
|
|
||||||
waitFor(event_base_, [&n_done]() { return n_done >= 2U; });
|
|
||||||
EXPECT_EQ(2U, n_done);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(EvDnsTest, canCancel)
|
|
||||||
{
|
|
||||||
auto dns = EvDns{ event_base_, tr_time };
|
|
||||||
auto n_done = size_t{ 0 };
|
|
||||||
static auto constexpr Name = "example.com"sv;
|
|
||||||
|
|
||||||
auto tag = dns.lookup(
|
|
||||||
Name,
|
|
||||||
[&n_done](struct sockaddr const* ai, socklen_t ailen, time_t expires_at)
|
|
||||||
{
|
|
||||||
++n_done;
|
|
||||||
// we cancelled this req, so `ai` and `ailen` should be zeroed out
|
|
||||||
EXPECT_EQ(nullptr, ai);
|
|
||||||
EXPECT_EQ(0, ailen);
|
|
||||||
EXPECT_EQ(0, expires_at);
|
|
||||||
});
|
|
||||||
|
|
||||||
dns.lookup(
|
|
||||||
Name,
|
|
||||||
[&n_done](struct sockaddr const* ai, socklen_t ailen, time_t expires_at)
|
|
||||||
{
|
|
||||||
++n_done;
|
|
||||||
|
|
||||||
// this one did _not_ get cancelled so it should be OK
|
|
||||||
EXPECT_NE(nullptr, ai);
|
|
||||||
EXPECT_GT(ailen, 0);
|
|
||||||
EXPECT_GT(expires_at, tr_time());
|
|
||||||
});
|
|
||||||
|
|
||||||
dns.cancel(tag);
|
|
||||||
|
|
||||||
// wait for both callbacks to be called
|
|
||||||
waitFor(event_base_, [&n_done]() { return n_done >= 2U; });
|
|
||||||
EXPECT_EQ(2U, n_done);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(EvDnsTest, doesCacheEntries)
|
|
||||||
{
|
|
||||||
auto dns = EvDns{ event_base_, tr_time };
|
|
||||||
static auto constexpr Name = "example.com"sv;
|
|
||||||
|
|
||||||
struct sockaddr const* ai_addr = nullptr;
|
|
||||||
|
|
||||||
dns.lookup(
|
|
||||||
Name,
|
|
||||||
[&ai_addr](struct sockaddr const* ai, socklen_t ailen, time_t expires_at)
|
|
||||||
{
|
|
||||||
EXPECT_NE(nullptr, ai);
|
|
||||||
EXPECT_GT(ailen, 0);
|
|
||||||
EXPECT_GT(expires_at, tr_time());
|
|
||||||
ai_addr = ai;
|
|
||||||
});
|
|
||||||
|
|
||||||
// wait for the lookup
|
|
||||||
waitFor(event_base_, [&ai_addr]() { return ai_addr != nullptr; });
|
|
||||||
ASSERT_NE(nullptr, ai_addr);
|
|
||||||
|
|
||||||
auto second_callback_called = false;
|
|
||||||
dns.lookup(
|
|
||||||
Name,
|
|
||||||
[&ai_addr, &second_callback_called](struct sockaddr const* ai, socklen_t ailen, time_t expires_at)
|
|
||||||
{
|
|
||||||
EXPECT_NE(nullptr, ai);
|
|
||||||
EXPECT_GT(ailen, 0);
|
|
||||||
EXPECT_EQ(ai_addr, ai);
|
|
||||||
EXPECT_GT(expires_at, tr_time());
|
|
||||||
second_callback_called = true;
|
|
||||||
});
|
|
||||||
// since it's cached, the callback should have been invoked
|
|
||||||
// without waiting for the event loop
|
|
||||||
EXPECT_TRUE(second_callback_called);
|
|
||||||
|
|
||||||
// confirm that `cached()` returns the cached value immediately
|
|
||||||
auto res = dns.cached(Name);
|
|
||||||
EXPECT_TRUE(res);
|
|
||||||
EXPECT_EQ(ai_addr, res->first);
|
|
||||||
EXPECT_GT(res->second, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace libtransmission::test
|
|
||||||
@@ -55,7 +55,7 @@ TEST_F(NetTest, compact4)
|
|||||||
auto compact4 = std::array<std::byte, 6>{};
|
auto compact4 = std::array<std::byte, 6>{};
|
||||||
auto out = std::data(compact4);
|
auto out = std::data(compact4);
|
||||||
out = addr.toCompact4(out, port);
|
out = addr.toCompact4(out, port);
|
||||||
EXPECT_EQ(std::size(Compact4), out - std::data(compact4));
|
EXPECT_EQ(std::size(Compact4), static_cast<size_t>(out - std::data(compact4)));
|
||||||
EXPECT_EQ(Compact4, compact4);
|
EXPECT_EQ(Compact4, compact4);
|
||||||
|
|
||||||
/// sockaddr --> compact
|
/// sockaddr --> compact
|
||||||
|
|||||||
@@ -327,7 +327,7 @@ TEST_F(SettingsTest, canSaveSizeT)
|
|||||||
settings.save(&dict);
|
settings.save(&dict);
|
||||||
auto val = int64_t{};
|
auto val = int64_t{};
|
||||||
EXPECT_TRUE(tr_variantDictFindInt(&dict, Key, &val));
|
EXPECT_TRUE(tr_variantDictFindInt(&dict, Key, &val));
|
||||||
EXPECT_EQ(expected_value, val);
|
EXPECT_EQ(expected_value, static_cast<size_t>(val));
|
||||||
tr_variantClear(&dict);
|
tr_variantClear(&dict);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user