Minor GetHostByName improvements.

GitOrigin-RevId: ff61c5aa543067e855a6f4a7f25c579a8c17aa87
This commit is contained in:
levlam 2019-01-24 20:08:29 +03:00
parent bc838db8ec
commit 12ffc22483
4 changed files with 32 additions and 22 deletions

View File

@ -6,16 +6,17 @@
// //
#include "td/net/GetHostByNameActor.h" #include "td/net/GetHostByNameActor.h"
#include "td/net/Wget.h"
#include "td/utils/JsonBuilder.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include "td/utils/Time.h" #include "td/utils/Time.h"
#include "td/utils/JsonBuilder.h"
#include "td/net/Wget.h"
namespace td { namespace td {
namespace detail { namespace detail {
class GoogleDnsResolver : public Actor { class GoogleDnsResolver : public Actor {
public: public:
GoogleDnsResolver(std::string host, GetHostByNameActor::ResolveOptions options, td::Promise<td::IPAddress> promise) GoogleDnsResolver(std::string host, GetHostByNameActor::ResolveOptions options, Promise<IPAddress> promise)
: host_(std::move(host)), options_(std::move(options)), promise_(std::move(promise)) { : host_(std::move(host)), options_(std::move(options)), promise_(std::move(promise)) {
} }
@ -44,13 +45,14 @@ class GoogleDnsResolver : public Actor {
return Status::Error("Failed to parse dns result: not an object"); return Status::Error("Failed to parse dns result: not an object");
} }
TRY_RESULT(answer, get_json_object_field(json_value.get_object(), "Answer", JsonValue::Type::Array, false)); TRY_RESULT(answer, get_json_object_field(json_value.get_object(), "Answer", JsonValue::Type::Array, false));
if (answer.get_array().size() == 0) { auto &array = answer.get_array();
if (array.size() == 0) {
return Status::Error("Failed to parse dns result: Answer is an empty array"); return Status::Error("Failed to parse dns result: Answer is an empty array");
} }
if (answer.get_array()[0].type() != JsonValue::Type::Object) { if (array[0].type() != JsonValue::Type::Object) {
return Status::Error("Failed to parse dns result: Answer[0] is not an object"); return Status::Error("Failed to parse dns result: Answer[0] is not an object");
} }
auto &answer_0 = answer.get_array()[0].get_object(); auto &answer_0 = array[0].get_object();
TRY_RESULT(ip_str, get_json_object_string_field(answer_0, "data", false)); TRY_RESULT(ip_str, get_json_object_string_field(answer_0, "data", false));
IPAddress ip; IPAddress ip;
TRY_STATUS(ip.init_host_port(ip_str, 0)); TRY_STATUS(ip.init_host_port(ip_str, 0));
@ -59,9 +61,10 @@ class GoogleDnsResolver : public Actor {
}); });
} }
}; };
class NativeDnsResolver : public Actor { class NativeDnsResolver : public Actor {
public: public:
NativeDnsResolver(std::string host, GetHostByNameActor::ResolveOptions options, td::Promise<td::IPAddress> promise) NativeDnsResolver(std::string host, GetHostByNameActor::ResolveOptions options, Promise<IPAddress> promise)
: host_(std::move(host)), options_(std::move(options)), promise_(std::move(promise)) { : host_(std::move(host)), options_(std::move(options)), promise_(std::move(promise)) {
} }
@ -72,9 +75,9 @@ class NativeDnsResolver : public Actor {
void start_up() override { void start_up() override {
IPAddress ip; IPAddress ip;
auto begin_time = td::Time::now(); auto begin_time = Time::now();
auto status = ip.init_host_port(host_, 0, options_.prefer_ipv6); auto status = ip.init_host_port(host_, 0, options_.prefer_ipv6);
auto end_time = td::Time::now(); auto end_time = Time::now();
LOG(WARNING) << "Init host = " << host_ << " in " << end_time - begin_time << " seconds to " << ip; LOG(WARNING) << "Init host = " << host_ << " in " << end_time - begin_time << " seconds to " << ip;
if (status.is_error()) { if (status.is_error()) {
promise_.set_error(std::move(status)); promise_.set_error(std::move(status));
@ -84,9 +87,10 @@ class NativeDnsResolver : public Actor {
stop(); stop();
} }
}; };
class DnsResolver : public Actor { class DnsResolver : public Actor {
public: public:
DnsResolver(std::string host, GetHostByNameActor::ResolveOptions options, td::Promise<td::IPAddress> promise) DnsResolver(std::string host, GetHostByNameActor::ResolveOptions options, Promise<IPAddress> promise)
: host_(std::move(host)), options_(std::move(options)), promise_(std::move(promise)) { : host_(std::move(host)), options_(std::move(options)), promise_(std::move(promise)) {
} }
@ -126,6 +130,7 @@ class DnsResolver : public Actor {
} // namespace detail } // namespace detail
GetHostByNameActor::Options::Options() = default; GetHostByNameActor::Options::Options() = default;
ActorOwn<> GetHostByNameActor::resolve(std::string host, ResolveOptions options, Promise<IPAddress> promise) { ActorOwn<> GetHostByNameActor::resolve(std::string host, ResolveOptions options, Promise<IPAddress> promise) {
switch (options.type) { switch (options.type) {
case Native: case Native:
@ -137,6 +142,9 @@ ActorOwn<> GetHostByNameActor::resolve(std::string host, ResolveOptions options,
case All: case All:
return ActorOwn<>(create_actor_on_scheduler<detail::DnsResolver>("DnsResolver", options.scheduler_id, return ActorOwn<>(create_actor_on_scheduler<detail::DnsResolver>("DnsResolver", options.scheduler_id,
std::move(host), options, std::move(promise))); std::move(host), options, std::move(promise)));
default:
UNREACHABLE();
return ActorOwn<>();
} }
} }
@ -147,7 +155,7 @@ void GetHostByNameActor::on_result(std::string host, bool prefer_ipv6, Result<IP
auto &value = cache_[prefer_ipv6].emplace(host, Value{{}, 0}).first->second; auto &value = cache_[prefer_ipv6].emplace(host, Value{{}, 0}).first->second;
auto promises = std::move(value.promises); auto promises = std::move(value.promises);
auto end_time = td::Time::now(); auto end_time = Time::now();
if (res.is_ok()) { if (res.is_ok()) {
value = Value{res.move_as_ok(), end_time + options_.ok_timeout}; value = Value{res.move_as_ok(), end_time + options_.ok_timeout};
} else { } else {
@ -160,7 +168,7 @@ void GetHostByNameActor::on_result(std::string host, bool prefer_ipv6, Result<IP
void GetHostByNameActor::run(string host, int port, bool prefer_ipv6, Promise<IPAddress> promise) { void GetHostByNameActor::run(string host, int port, bool prefer_ipv6, Promise<IPAddress> promise) {
auto &value = cache_[prefer_ipv6].emplace(host, Value{{}, 0}).first->second; auto &value = cache_[prefer_ipv6].emplace(host, Value{{}, 0}).first->second;
auto begin_time = td::Time::now(); auto begin_time = Time::now();
if (value.expire_at > begin_time) { if (value.expire_at > begin_time) {
return promise.set_result(value.get_ip_port(port)); return promise.set_result(value.get_ip_port(port));
} }

View File

@ -15,7 +15,8 @@
#include <unordered_map> #include <unordered_map>
namespace td { namespace td {
class GetHostByNameActor final : public td::Actor {
class GetHostByNameActor final : public Actor {
public: public:
enum ResolveType { Native, Google, All }; enum ResolveType { Native, Google, All };
struct Options { struct Options {
@ -26,27 +27,27 @@ class GetHostByNameActor final : public td::Actor {
int32 error_timeout{ERROR_CACHE_TIME}; int32 error_timeout{ERROR_CACHE_TIME};
}; };
explicit GetHostByNameActor(Options options = {}); explicit GetHostByNameActor(Options options = {});
void run(std::string host, int port, bool prefer_ipv6, td::Promise<td::IPAddress> promise); void run(std::string host, int port, bool prefer_ipv6, Promise<IPAddress> promise);
struct ResolveOptions { struct ResolveOptions {
ResolveType type{Native}; ResolveType type{Native};
bool prefer_ipv6; bool prefer_ipv6{false};
int scheduler_id{-1}; int scheduler_id{-1};
}; };
static TD_WARN_UNUSED_RESULT ActorOwn<> resolve(std::string host, ResolveOptions options, Promise<IPAddress> promise); static TD_WARN_UNUSED_RESULT ActorOwn<> resolve(std::string host, ResolveOptions options, Promise<IPAddress> promise);
private: private:
struct Value { struct Value {
Result<td::IPAddress> ip; Result<IPAddress> ip;
double expire_at; double expire_at;
ActorOwn<> query; ActorOwn<> query;
std::vector<std::pair<int, Promise<IPAddress>>> promises; std::vector<std::pair<int, Promise<IPAddress>>> promises;
Value(Result<td::IPAddress> ip, double expire_at) : ip(std::move(ip)), expire_at(expire_at) { Value(Result<IPAddress> ip, double expire_at) : ip(std::move(ip)), expire_at(expire_at) {
} }
Result<td::IPAddress> get_ip_port(int port) { Result<IPAddress> get_ip_port(int port) {
auto res = ip.clone(); auto res = ip.clone();
if (res.is_ok()) { if (res.is_ok()) {
res.ok_ref().set_port(port); res.ok_ref().set_port(port);

View File

@ -16,9 +16,9 @@
#include "td/mtproto/PingConnection.h" #include "td/mtproto/PingConnection.h"
#include "td/mtproto/RawConnection.h" #include "td/mtproto/RawConnection.h"
#include "td/net/GetHostByNameActor.h"
#include "td/net/Socks5.h" #include "td/net/Socks5.h"
#include "td/net/TransparentProxy.h" #include "td/net/TransparentProxy.h"
#include "td/net/GetHostByNameActor.h"
#include "td/telegram/ConfigManager.h" #include "td/telegram/ConfigManager.h"
#include "td/telegram/net/DcId.h" #include "td/telegram/net/DcId.h"
@ -74,10 +74,11 @@ TEST(Mtproto, GetHostByName) {
cnt--; cnt--;
sched.start(); sched.start();
while (sched.run_main(10)) { while (sched.run_main(10)) {
// empty; // empty
} }
sched.finish(); sched.finish();
} }
TEST(Mtproto, GetHostByNameActor) { TEST(Mtproto, GetHostByNameActor) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(WARNING)); SET_VERBOSITY_LEVEL(VERBOSITY_NAME(WARNING));
ConcurrentScheduler sched; ConcurrentScheduler sched;
@ -127,7 +128,7 @@ TEST(Mtproto, GetHostByNameActor) {
cnt--; cnt--;
sched.start(); sched.start();
while (sched.run_main(10)) { while (sched.run_main(10)) {
// empty; // empty
} }
sched.finish(); sched.finish();
} }