aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniil Cherednik <dan.cherednik@gmail.com>2022-07-06 23:04:30 +0300
committerDaniil Cherednik <dan.cherednik@gmail.com>2022-07-06 23:04:30 +0300
commit8b2fafa9888f6a85ad33912eccfb691f037fb285 (patch)
tree7beb62227739d1083b43993da45bf7e06810ebbd
parent08f543ac96eec65f35893e17a19dd1a10266b9d1 (diff)
downloadydb-8b2fafa9888f6a85ad33912eccfb691f037fb285.tar.gz
Missed changes for 33e0b0f01d29fe0a000c45feea0d5c855e0e78ae
x-ydb-stable-ref: b5a1b56ccae72d0629280e8a1247f041f9c72ce7
-rw-r--r--library/cpp/actors/dnsresolver/dnsresolver.cpp57
-rw-r--r--library/cpp/actors/dnsresolver/dnsresolver_caching.cpp376
-rw-r--r--library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp134
-rw-r--r--library/cpp/actors/interconnect/events_local.h2
-rw-r--r--library/cpp/actors/interconnect/interconnect_address.cpp12
-rw-r--r--library/cpp/actors/interconnect/interconnect_address.h2
-rw-r--r--library/cpp/actors/interconnect/interconnect_handshake.cpp62
-rw-r--r--library/cpp/actors/interconnect/interconnect_resolve.cpp54
8 files changed, 368 insertions, 331 deletions
diff --git a/library/cpp/actors/dnsresolver/dnsresolver.cpp b/library/cpp/actors/dnsresolver/dnsresolver.cpp
index 6329bb0083..abd90182e1 100644
--- a/library/cpp/actors/dnsresolver/dnsresolver.cpp
+++ b/library/cpp/actors/dnsresolver/dnsresolver.cpp
@@ -264,7 +264,7 @@ namespace NDnsResolver {
auto reqCtx = MakeIntrusive<TRequestContext>(
this, TActivationContext::ActorSystem(), SelfId(), ev->Sender, ev->Cookie, ERequestType::GetHostByName);
PushCallback([this, reqCtx = std::move(reqCtx), name = std::move(msg->Name), family = msg->Family] () mutable {
- StartGetHostByName(std::move(reqCtx), std::move(name), family);
+ StartGetAddrInfo(std::move(reqCtx), std::move(name), family);
});
}
@@ -273,18 +273,28 @@ namespace NDnsResolver {
auto reqCtx = MakeIntrusive<TRequestContext>(
this, TActivationContext::ActorSystem(), SelfId(), ev->Sender, ev->Cookie, ERequestType::GetAddr);
PushCallback([this, reqCtx = std::move(reqCtx), name = std::move(msg->Name), family = msg->Family] () mutable {
- StartGetHostByName(std::move(reqCtx), std::move(name), family);
+ StartGetAddrInfo(std::move(reqCtx), std::move(name), family);
});
}
- void StartGetHostByName(TRequestContext::TPtr reqCtx, TString name, int family) noexcept {
+ void StartGetAddrInfo(TRequestContext::TPtr reqCtx, TString name, int family) noexcept {
reqCtx->Ref();
- ares_gethostbyname(AresChannel, name.c_str(), family,
- &TThis::GetHostByNameAresCallback, reqCtx.Get());
+ ares_addrinfo_hints hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = ARES_AI_NOSORT;
+ hints.ai_family = family;
+ ares_getaddrinfo(AresChannel, name.c_str(), nullptr, &hints, &TThis::GetAddrInfoAresCallback, reqCtx.Get());
}
private:
- static void GetHostByNameAresCallback(void* arg, int status, int timeouts, struct hostent* info) {
+ static void GetAddrInfoAresCallback(void* arg, int status, int timeouts, ares_addrinfo *result) {
+ struct TDeleter {
+ void operator ()(ares_addrinfo *ptr) const {
+ ares_freeaddrinfo(ptr);
+ }
+ };
+ std::unique_ptr<ares_addrinfo, TDeleter> ptr(result);
+
Y_UNUSED(timeouts);
TRequestContext::TPtr reqCtx(static_cast<TRequestContext*>(arg));
reqCtx->UnRef();
@@ -297,22 +307,20 @@ namespace NDnsResolver {
switch (reqCtx->Type) {
case ERequestType::GetHostByName: {
auto result = MakeHolder<TEvDns::TEvGetHostByNameResult>();
- if (status == 0) {
- switch (info->h_addrtype) {
- case AF_INET: {
- for (int i = 0; info->h_addr_list[i] != nullptr; ++i) {
- result->AddrsV4.emplace_back(*(struct in_addr*)(info->h_addr_list[i]));
+ if (status == ARES_SUCCESS) {
+ for (auto *node = ptr->nodes; node; node = node->ai_next) {
+ switch (node->ai_family) {
+ case AF_INET: {
+ result->AddrsV4.emplace_back(((sockaddr_in*)node->ai_addr)->sin_addr);
+ break;
}
- break;
- }
- case AF_INET6: {
- for (int i = 0; info->h_addr_list[i] != nullptr; ++i) {
- result->AddrsV6.emplace_back(*(struct in6_addr*)(info->h_addr_list[i]));
+ case AF_INET6: {
+ result->AddrsV6.emplace_back(((sockaddr_in6*)node->ai_addr)->sin6_addr);
+ break;
}
- break;
+ default:
+ Y_FAIL("unknown address family in ares callback");
}
- default:
- Y_FAIL("unknown address family in ares callback");
}
} else {
result->ErrorText = ares_strerror(status);
@@ -325,17 +333,18 @@ namespace NDnsResolver {
case ERequestType::GetAddr: {
auto result = MakeHolder<TEvDns::TEvGetAddrResult>();
- if (status == 0 && Y_UNLIKELY(info->h_addr_list[0] == nullptr)) {
+ if (status == ARES_SUCCESS && Y_UNLIKELY(ptr->nodes == nullptr)) {
status = ARES_ENODATA;
}
- if (status == 0) {
- switch (info->h_addrtype) {
+ if (status == ARES_SUCCESS) {
+ auto *node = ptr->nodes;
+ switch (node->ai_family) {
case AF_INET: {
- result->Addr = *(struct in_addr*)(info->h_addr_list[0]);
+ result->Addr = ((sockaddr_in*)node->ai_addr)->sin_addr;
break;
}
case AF_INET6: {
- result->Addr = *(struct in6_addr*)(info->h_addr_list[0]);
+ result->Addr = ((sockaddr_in6*)node->ai_addr)->sin6_addr;
break;
}
default:
diff --git a/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp b/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp
index 02760f4c27..a7e38806c0 100644
--- a/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp
+++ b/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp
@@ -15,10 +15,13 @@ namespace NDnsResolver {
struct TMonCounters {
NMonitoring::TDynamicCounters::TCounterPtr OutgoingInFlightV4;
NMonitoring::TDynamicCounters::TCounterPtr OutgoingInFlightV6;
+ NMonitoring::TDynamicCounters::TCounterPtr OutgoingInFlightUnspec;
NMonitoring::TDynamicCounters::TCounterPtr OutgoingErrorsV4;
NMonitoring::TDynamicCounters::TCounterPtr OutgoingErrorsV6;
+ NMonitoring::TDynamicCounters::TCounterPtr OutgoingErrorsUnspec;
NMonitoring::TDynamicCounters::TCounterPtr OutgoingTotalV4;
NMonitoring::TDynamicCounters::TCounterPtr OutgoingTotalV6;
+ NMonitoring::TDynamicCounters::TCounterPtr OutgoingTotalUnspec;
NMonitoring::TDynamicCounters::TCounterPtr IncomingInFlight;
NMonitoring::TDynamicCounters::TCounterPtr IncomingErrors;
@@ -31,10 +34,13 @@ namespace NDnsResolver {
TMonCounters(const NMonitoring::TDynamicCounterPtr& counters)
: OutgoingInFlightV4(counters->GetCounter("DnsResolver/Outgoing/InFlight/V4", false))
, OutgoingInFlightV6(counters->GetCounter("DnsResolver/Outgoing/InFlight/V6", false))
+ , OutgoingInFlightUnspec(counters->GetCounter("DnsResolver/Outgoing/InFlight/Unspec", false))
, OutgoingErrorsV4(counters->GetCounter("DnsResolver/Outgoing/Errors/V4", true))
, OutgoingErrorsV6(counters->GetCounter("DnsResolver/Outgoing/Errors/V6", true))
+ , OutgoingErrorsUnspec(counters->GetCounter("DnsResolver/Outgoing/Errors/Unspec", true))
, OutgoingTotalV4(counters->GetCounter("DnsResolver/Outgoing/Total/V4", true))
, OutgoingTotalV6(counters->GetCounter("DnsResolver/Outgoing/Total/V6", true))
+ , OutgoingTotalUnspec(counters->GetCounter("DnsResolver/Outgoing/Total/Unspec", true))
, IncomingInFlight(counters->GetCounter("DnsResolver/Incoming/InFlight", false))
, IncomingErrors(counters->GetCounter("DnsResolver/Incoming/Errors", true))
, IncomingTotal(counters->GetCounter("DnsResolver/Incoming/Total", true))
@@ -42,6 +48,45 @@ namespace NDnsResolver {
, CacheHits(counters->GetCounter("DnsResolver/Cache/Hits", true))
, CacheMisses(counters->GetCounter("DnsResolver/Cache/Misses", true))
{ }
+
+ const NMonitoring::TDynamicCounters::TCounterPtr& OutgoingInFlightByFamily(int family) const {
+ switch (family) {
+ case AF_INET:
+ return OutgoingInFlightV4;
+ case AF_INET6:
+ return OutgoingInFlightV6;
+ case AF_UNSPEC:
+ return OutgoingInFlightUnspec;
+ default:
+ Y_FAIL("Unexpected family %d", family);
+ }
+ }
+
+ const NMonitoring::TDynamicCounters::TCounterPtr& OutgoingErrorsByFamily(int family) const {
+ switch (family) {
+ case AF_INET:
+ return OutgoingErrorsV4;
+ case AF_INET6:
+ return OutgoingErrorsV6;
+ case AF_UNSPEC:
+ return OutgoingErrorsUnspec;
+ default:
+ Y_FAIL("Unexpected family %d", family);
+ }
+ }
+
+ const NMonitoring::TDynamicCounters::TCounterPtr& OutgoingTotalByFamily(int family) const {
+ switch (family) {
+ case AF_INET:
+ return OutgoingTotalV4;
+ case AF_INET6:
+ return OutgoingTotalV6;
+ case AF_UNSPEC:
+ return OutgoingTotalUnspec;
+ default:
+ Y_FAIL("Unexpected family %d", family);
+ }
+ }
};
public:
@@ -97,19 +142,13 @@ namespace NDnsResolver {
WaitingRequests.erase(waitingIt);
switch (waitingInfo.Family) {
+ case AF_UNSPEC:
case AF_INET6:
- if (ev->Get()->Status) {
- ProcessErrorV6(waitingInfo.Position, ev->Get()->Status, std::move(ev->Get()->ErrorText));
- } else {
- ProcessAddrsV6(waitingInfo.Position, std::move(ev->Get()->AddrsV6));
- }
- break;
-
case AF_INET:
if (ev->Get()->Status) {
- ProcessErrorV4(waitingInfo.Position, ev->Get()->Status, std::move(ev->Get()->ErrorText));
+ ProcessError(waitingInfo.Family, waitingInfo.Position, ev->Get()->Status, std::move(ev->Get()->ErrorText));
} else {
- ProcessAddrsV4(waitingInfo.Position, std::move(ev->Get()->AddrsV4));
+ ProcessAddrs(waitingInfo.Family, waitingInfo.Position, std::move(ev->Get()->AddrsV6), std::move(ev->Get()->AddrsV4));
}
break;
@@ -127,12 +166,12 @@ namespace NDnsResolver {
WaitingRequests.erase(waitingIt);
switch (waitingInfo.Family) {
+ case AF_UNSPEC:
case AF_INET6:
- ProcessErrorV6(waitingInfo.Position, ARES_ENOTINITIALIZED, "Caching dns resolver cannot deliver to the underlying resolver");
- break;
case AF_INET:
- ProcessErrorV4(waitingInfo.Position, ARES_ENOTINITIALIZED, "Caching dns resolver cannot deliver to the underlying resolver");
+ ProcessError(waitingInfo.Family, waitingInfo.Position, ARES_ENOTINITIALIZED, "Caching dns resolver cannot deliver to the underlying resolver");
break;
+
default:
Y_FAIL("Unexpected request family %d", waitingInfo.Family);
}
@@ -170,26 +209,30 @@ namespace NDnsResolver {
switch (req->Family) {
case AF_UNSPEC:
+ if (Options.AllowIPv6 && Options.AllowIPv4) {
+ EnqueueRequest(AF_UNSPEC, std::move(req));
+ return;
+ }
if (Options.AllowIPv6) {
- EnqueueRequestIPv6(std::move(req));
+ EnqueueRequest(AF_INET6, std::move(req));
return;
}
if (Options.AllowIPv4) {
- EnqueueRequestIPv4(std::move(req));
+ EnqueueRequest(AF_INET, std::move(req));
return;
}
break;
case AF_INET6:
if (Options.AllowIPv6) {
- EnqueueRequestIPv6(std::move(req));
+ EnqueueRequest(AF_INET6, std::move(req));
return;
}
break;
case AF_INET:
if (Options.AllowIPv4) {
- EnqueueRequestIPv4(std::move(req));
+ EnqueueRequest(AF_INET, std::move(req));
return;
}
break;
@@ -198,7 +241,7 @@ namespace NDnsResolver {
ReplyWithError(std::move(req), ARES_EBADFAMILY);
}
- void EnqueueRequestIPv6(THolder<TIncomingRequest> req) {
+ void EnqueueRequest(int family, THolder<TIncomingRequest> req) {
auto now = TActivationContext::Now();
auto& fullState = NameToState[req->Name];
@@ -206,72 +249,33 @@ namespace NDnsResolver {
*MonCounters->CacheSize = NameToState.size();
}
- auto& state = fullState.StateIPv6;
- EnsureRequest(state, req->Name, AF_INET6, now);
+ auto& state = fullState.StateByFamily(family);
+ EnsureRequest(state, req->Name, family, now);
if (state.IsHardExpired(now)) {
Y_VERIFY(state.Waiting);
if (MonCounters) {
++*MonCounters->CacheMisses;
}
- // We need to wait for ipv6 reply, schedule ipv4 request in parallel if needed
- if (Options.AllowIPv4) {
- EnsureRequest(fullState.StateIPv4, req->Name, AF_INET, now);
- }
state.WaitingRequests.PushBack(req.Release());
return;
}
- // We want to retry AF_UNSPEC with IPv4 in some cases
- if (req->Family == AF_UNSPEC && Options.AllowIPv4 && state.RetryUnspec()) {
- EnqueueRequestIPv4(std::move(req));
- return;
- }
-
- if (MonCounters) {
- ++*MonCounters->CacheHits;
- }
-
- if (state.Status != 0) {
- ReplyWithError(std::move(req), state.Status, state.ErrorText);
- } else {
- ReplyWithAddrs(std::move(req), fullState.AddrsIPv6);
- }
- }
-
- void EnqueueRequestIPv4(THolder<TIncomingRequest> req, bool isCacheMiss = false) {
- auto now = TActivationContext::Now();
-
- auto& fullState = NameToState[req->Name];
if (MonCounters) {
- *MonCounters->CacheSize = NameToState.size();
- }
-
- auto& state = fullState.StateIPv4;
- EnsureRequest(state, req->Name, AF_INET, now);
-
- if (state.IsHardExpired(now)) {
- Y_VERIFY(state.Waiting);
- if (MonCounters && !isCacheMiss) {
- ++*MonCounters->CacheMisses;
- }
- state.WaitingRequests.PushBack(req.Release());
- return;
- }
-
- if (MonCounters && !isCacheMiss) {
++*MonCounters->CacheHits;
}
if (state.Status != 0) {
ReplyWithError(std::move(req), state.Status, state.ErrorText);
} else {
- ReplyWithAddrs(std::move(req), fullState.AddrsIPv4);
+ ReplyWithAddrs(std::move(req), state.AddrsIPv6, state.AddrsIPv4);
}
}
private:
struct TFamilyState {
+ TVector<struct in6_addr> AddrsIPv6;
+ TVector<struct in_addr> AddrsIPv4;
TIncomingRequestList WaitingRequests;
TInstant SoftDeadline;
TInstant HardDeadline;
@@ -287,13 +291,6 @@ namespace NDnsResolver {
return InSoftHeap || InHardHeap || Waiting;
}
- bool RetryUnspec() const {
- return (
- Status == ARES_ENODATA ||
- Status == ARES_EBADRESP ||
- Status == ARES_ETIMEOUT);
- }
-
bool ServerReplied() const {
return ServerReplied(Status);
}
@@ -315,13 +312,38 @@ namespace NDnsResolver {
};
struct TState {
+ TFamilyState StateUnspec;
TFamilyState StateIPv6;
TFamilyState StateIPv4;
- TVector<struct in6_addr> AddrsIPv6;
- TVector<struct in_addr> AddrsIPv4;
bool Needed() const {
- return StateIPv6.Needed() || StateIPv4.Needed();
+ return StateUnspec.Needed() || StateIPv6.Needed() || StateIPv4.Needed();
+ }
+
+ const TFamilyState& StateByFamily(int family) const {
+ switch (family) {
+ case AF_UNSPEC:
+ return StateUnspec;
+ case AF_INET6:
+ return StateIPv6;
+ case AF_INET:
+ return StateIPv4;
+ default:
+ Y_FAIL("Unsupported family %d", family);
+ }
+ }
+
+ TFamilyState& StateByFamily(int family) {
+ switch (family) {
+ case AF_UNSPEC:
+ return StateUnspec;
+ case AF_INET6:
+ return StateIPv6;
+ case AF_INET:
+ return StateIPv4;
+ default:
+ Y_FAIL("Unsupported family %d", family);
+ }
}
};
@@ -366,16 +388,8 @@ namespace NDnsResolver {
}
if (MonCounters) {
- switch (family) {
- case AF_INET6:
- ++*MonCounters->OutgoingInFlightV6;
- ++*MonCounters->OutgoingTotalV6;
- break;
- case AF_INET:
- ++*MonCounters->OutgoingInFlightV4;
- ++*MonCounters->OutgoingTotalV4;
- break;
- }
+ ++*MonCounters->OutgoingInFlightByFamily(family);
+ ++*MonCounters->OutgoingTotalByFamily(family);
}
ui64 reqId = ++LastRequestId;
@@ -406,6 +420,14 @@ namespace NDnsResolver {
}
}
+ void PushSoftUnspec(TNameToState::iterator it, TInstant newDeadline) {
+ PushToHeap<&TState::StateUnspec, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapUnspec, it, newDeadline);
+ }
+
+ void PushHardUnspec(TNameToState::iterator it, TInstant newDeadline) {
+ PushToHeap<&TState::StateUnspec, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapUnspec, it, newDeadline);
+ }
+
void PushSoftV6(TNameToState::iterator it, TInstant newDeadline) {
PushToHeap<&TState::StateIPv6, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv6, it, newDeadline);
}
@@ -422,162 +444,111 @@ namespace NDnsResolver {
PushToHeap<&TState::StateIPv4, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv4, it, newDeadline);
}
- void ProcessErrorV6(TNameToState::iterator it, int status, TString errorText) {
- auto now = TActivationContext::Now();
- if (MonCounters) {
- --*MonCounters->OutgoingInFlightV6;
- ++*MonCounters->OutgoingErrorsV6;
- }
-
- auto& state = it->second.StateIPv6;
- Y_VERIFY(state.Waiting, "Got error for a state we are not waiting");
- state.Waiting = false;
-
- // When we have a cached positive reply, don't overwrite it with spurious errors
- const bool serverReplied = TFamilyState::ServerReplied(status);
- if (!serverReplied && state.ServerReplied() && !state.IsHardExpired(now)) {
- PushSoftV6(it, now + Options.SoftNegativeExpireTime);
- if (state.Status == ARES_SUCCESS) {
- SendAddrsV6(it);
- } else {
- SendErrorsV6(it, now);
- }
- return;
- }
-
- state.Status = status;
- state.ErrorText = std::move(errorText);
- PushSoftV6(it, now + Options.SoftNegativeExpireTime);
- if (serverReplied) {
- // Server actually replied, so keep it cached for longer
- PushHardV6(it, now + Options.HardPositiveExpireTime);
- } else {
- PushHardV6(it, now + Options.HardNegativeExpireTime);
+ void PushSoft(int family, TNameToState::iterator it, TInstant newDeadline) {
+ switch (family) {
+ case AF_UNSPEC:
+ PushSoftUnspec(it, newDeadline);
+ break;
+ case AF_INET6:
+ PushSoftV6(it, newDeadline);
+ break;
+ case AF_INET:
+ PushSoftV4(it, newDeadline);
+ break;
+ default:
+ Y_FAIL("Unexpected family %d", family);
}
-
- SendErrorsV6(it, now);
}
- void SendErrorsV6(TNameToState::iterator it, TInstant now) {
- bool cleaned = false;
- auto& state = it->second.StateIPv6;
- while (state.WaitingRequests) {
- THolder<TIncomingRequest> req(state.WaitingRequests.PopFront());
- if (req->Family == AF_UNSPEC && Options.AllowIPv4 && state.RetryUnspec()) {
- if (!cleaned) {
- CleanupExpired(now);
- cleaned = true;
- }
- EnqueueRequestIPv4(std::move(req), /* isCacheMiss */ true);
- } else {
- ReplyWithError(std::move(req), state.Status, state.ErrorText);
- }
+ void PushHard(int family, TNameToState::iterator it, TInstant newDeadline) {
+ switch (family) {
+ case AF_UNSPEC:
+ PushHardUnspec(it, newDeadline);
+ break;
+ case AF_INET6:
+ PushHardV6(it, newDeadline);
+ break;
+ case AF_INET:
+ PushHardV4(it, newDeadline);
+ break;
+ default:
+ Y_FAIL("Unexpected family %d", family);
}
}
- void ProcessErrorV4(TNameToState::iterator it, int status, TString errorText) {
+ void ProcessError(int family, TNameToState::iterator it, int status, TString errorText) {
auto now = TActivationContext::Now();
if (MonCounters) {
- --*MonCounters->OutgoingInFlightV4;
- ++*MonCounters->OutgoingErrorsV4;
+ --*MonCounters->OutgoingInFlightByFamily(family);
+ ++*MonCounters->OutgoingErrorsByFamily(family);
}
- auto& state = it->second.StateIPv4;
+ auto& state = it->second.StateByFamily(family);
Y_VERIFY(state.Waiting, "Got error for a state we are not waiting");
state.Waiting = false;
// When we have a cached positive reply, don't overwrite it with spurious errors
const bool serverReplied = TFamilyState::ServerReplied(status);
if (!serverReplied && state.ServerReplied() && !state.IsHardExpired(now)) {
- PushSoftV4(it, now + Options.SoftNegativeExpireTime);
+ PushSoft(family, it, now + Options.SoftNegativeExpireTime);
if (state.Status == ARES_SUCCESS) {
- SendAddrsV4(it);
+ SendAddrs(family, it);
} else {
- SendErrorsV4(it);
+ SendErrors(family, it);
}
return;
}
state.Status = status;
state.ErrorText = std::move(errorText);
- PushSoftV4(it, now + Options.SoftNegativeExpireTime);
+ PushSoft(family, it, now + Options.SoftNegativeExpireTime);
if (serverReplied) {
// Server actually replied, so keep it cached for longer
- PushHardV4(it, now + Options.HardPositiveExpireTime);
+ PushHard(family, it, now + Options.HardPositiveExpireTime);
} else {
- PushHardV4(it, now + Options.HardNegativeExpireTime);
+ PushHard(family, it, now + Options.HardNegativeExpireTime);
}
- SendErrorsV4(it);
+ SendErrors(family, it);
}
- void SendErrorsV4(TNameToState::iterator it) {
- auto& state = it->second.StateIPv4;
+ void SendErrors(int family, TNameToState::iterator it) {
+ auto& state = it->second.StateByFamily(family);
while (state.WaitingRequests) {
THolder<TIncomingRequest> req(state.WaitingRequests.PopFront());
ReplyWithError(std::move(req), state.Status, state.ErrorText);
}
}
- void ProcessAddrsV6(TNameToState::iterator it, TVector<struct in6_addr> addrs) {
- if (Y_UNLIKELY(addrs.empty())) {
- // Probably unnecessary: we don't want to deal with empty address lists
- return ProcessErrorV6(it, ARES_ENODATA, ares_strerror(ARES_ENODATA));
- }
-
- auto now = TActivationContext::Now();
- if (MonCounters) {
- --*MonCounters->OutgoingInFlightV6;
- }
-
- auto& state = it->second.StateIPv6;
- Y_VERIFY(state.Waiting, "Got reply for a state we are not waiting");
- state.Waiting = false;
-
- state.Status = ARES_SUCCESS;
- it->second.AddrsIPv6 = std::move(addrs);
- PushSoftV6(it, now + Options.SoftPositiveExpireTime);
- PushHardV6(it, now + Options.HardPositiveExpireTime);
-
- SendAddrsV6(it);
- }
-
- void SendAddrsV6(TNameToState::iterator it) {
- auto& state = it->second.StateIPv6;
- while (state.WaitingRequests) {
- THolder<TIncomingRequest> req(state.WaitingRequests.PopFront());
- ReplyWithAddrs(std::move(req), it->second.AddrsIPv6);
- }
- }
-
- void ProcessAddrsV4(TNameToState::iterator it, TVector<struct in_addr> addrs) {
- if (Y_UNLIKELY(addrs.empty())) {
+ void ProcessAddrs(int family, TNameToState::iterator it, TVector<struct in6_addr> addrs6, TVector<struct in_addr> addrs4) {
+ if (Y_UNLIKELY(addrs6.empty() && addrs4.empty())) {
// Probably unnecessary: we don't want to deal with empty address lists
- return ProcessErrorV4(it, ARES_ENODATA, ares_strerror(ARES_ENODATA));
+ return ProcessError(family, it, ARES_ENODATA, ares_strerror(ARES_ENODATA));
}
auto now = TActivationContext::Now();
if (MonCounters) {
- --*MonCounters->OutgoingInFlightV4;
+ --*MonCounters->OutgoingInFlightByFamily(family);
}
- auto& state = it->second.StateIPv4;
+ auto& state = it->second.StateByFamily(family);
Y_VERIFY(state.Waiting, "Got reply for a state we are not waiting");
state.Waiting = false;
state.Status = ARES_SUCCESS;
- it->second.AddrsIPv4 = std::move(addrs);
- PushSoftV4(it, now + Options.SoftPositiveExpireTime);
- PushHardV4(it, now + Options.HardPositiveExpireTime);
+ state.AddrsIPv6 = std::move(addrs6);
+ state.AddrsIPv4 = std::move(addrs4);
+ PushSoft(family, it, now + Options.SoftPositiveExpireTime);
+ PushHard(family, it, now + Options.HardPositiveExpireTime);
- SendAddrsV4(it);
+ SendAddrs(family, it);
}
- void SendAddrsV4(TNameToState::iterator it) {
- auto& state = it->second.StateIPv4;
+ void SendAddrs(int family, TNameToState::iterator it) {
+ auto& state = it->second.StateByFamily(family);
while (state.WaitingRequests) {
THolder<TIncomingRequest> req(state.WaitingRequests.PopFront());
- ReplyWithAddrs(std::move(req), it->second.AddrsIPv4);
+ ReplyWithAddrs(std::move(req), state.AddrsIPv6, state.AddrsIPv4);
}
}
@@ -619,6 +590,8 @@ namespace NDnsResolver {
}
void CleanupExpired(TInstant now) {
+ DoCleanupExpired<&TState::StateUnspec, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapUnspec, now);
+ DoCleanupExpired<&TState::StateUnspec, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapUnspec, now);
DoCleanupExpired<&TState::StateIPv6, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv6, now);
DoCleanupExpired<&TState::StateIPv6, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv6, now);
DoCleanupExpired<&TState::StateIPv4, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv4, now);
@@ -649,36 +622,24 @@ namespace NDnsResolver {
}
}
- void ReplyWithAddrs(THolder<TIncomingRequest> req, const TVector<struct in6_addr>& addrs) {
- switch (req->Type) {
- case EIncomingRequestType::GetHostByName: {
- auto reply = MakeHolder<TEvDns::TEvGetHostByNameResult>();
- reply->AddrsV6 = addrs;
- Send(req->Sender, reply.Release(), 0, req->Cookie);
- break;
- }
- case EIncomingRequestType::GetAddr: {
- Y_VERIFY(!addrs.empty());
- auto reply = MakeHolder<TEvDns::TEvGetAddrResult>();
- reply->Addr = addrs.front();
- Send(req->Sender, reply.Release(), 0, req->Cookie);
- break;
- }
- }
- }
-
- void ReplyWithAddrs(THolder<TIncomingRequest> req, const TVector<struct in_addr>& addrs) {
+ void ReplyWithAddrs(THolder<TIncomingRequest> req, const TVector<struct in6_addr>& addrs6, const TVector<struct in_addr>& addrs4) {
switch (req->Type) {
case EIncomingRequestType::GetHostByName: {
auto reply = MakeHolder<TEvDns::TEvGetHostByNameResult>();
- reply->AddrsV4 = addrs;
+ reply->AddrsV6 = addrs6;
+ reply->AddrsV4 = addrs4;
Send(req->Sender, reply.Release(), 0, req->Cookie);
break;
}
case EIncomingRequestType::GetAddr: {
- Y_VERIFY(!addrs.empty());
auto reply = MakeHolder<TEvDns::TEvGetAddrResult>();
- reply->Addr = addrs.front();
+ if (!addrs6.empty()) {
+ reply->Addr = addrs6.front();
+ } else if (!addrs4.empty()) {
+ reply->Addr = addrs4.front();
+ } else {
+ Y_FAIL("Unexpected reply with empty address list");
+ }
Send(req->Sender, reply.Release(), 0, req->Cookie);
break;
}
@@ -698,6 +659,7 @@ namespace NDnsResolver {
void DropPending(int status, const TString& errorText) {
for (auto& [name, state] : NameToState) {
+ DropPending(state.StateUnspec.WaitingRequests, status, errorText);
DropPending(state.StateIPv6.WaitingRequests, status, errorText);
DropPending(state.StateIPv4.WaitingRequests, status, errorText);
}
@@ -713,6 +675,8 @@ namespace NDnsResolver {
const THolder<TMonCounters> MonCounters;
TNameToState NameToState;
+ TStateHeap<&TState::StateUnspec, &TFamilyState::SoftDeadline> SoftHeapUnspec;
+ TStateHeap<&TState::StateUnspec, &TFamilyState::HardDeadline> HardHeapUnspec;
TStateHeap<&TState::StateIPv6, &TFamilyState::SoftDeadline> SoftHeapIPv6;
TStateHeap<&TState::StateIPv6, &TFamilyState::HardDeadline> HardHeapIPv6;
TStateHeap<&TState::StateIPv4, &TFamilyState::SoftDeadline> SoftHeapIPv4;
diff --git a/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp b/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp
index c3b7cb3c77..89a7e9ab36 100644
--- a/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp
+++ b/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp
@@ -88,6 +88,18 @@ Y_UNIT_TEST_SUITE(CachingDnsResolver) {
static TMockReply SingleV4(const TString& addr, TDuration delay = DefaultDelay) {
return ManyV4({ addr }, delay);
}
+
+ friend TMockReply operator+(const TMockReply& a, const TMockReply& b) {
+ Y_VERIFY(a.Status == b.Status);
+ TMockReply result;
+ result.Status = a.Status;
+ result.Delay = Max(a.Delay, b.Delay);
+ result.AddrsV6.insert(result.AddrsV6.end(), a.AddrsV6.begin(), a.AddrsV6.end());
+ result.AddrsV6.insert(result.AddrsV6.end(), b.AddrsV6.begin(), b.AddrsV6.end());
+ result.AddrsV4.insert(result.AddrsV4.end(), a.AddrsV4.begin(), a.AddrsV4.end());
+ result.AddrsV4.insert(result.AddrsV4.end(), b.AddrsV4.begin(), b.AddrsV4.end());
+ return result;
+ }
};
using TMockDnsCallback = std::function<TMockReply (const TString&, int)>;
@@ -166,8 +178,10 @@ Y_UNIT_TEST_SUITE(CachingDnsResolver) {
TActorId Sleeper;
TString Section_;
+ NMonitoring::TDynamicCounters::TCounterPtr InFlightUnspec;
NMonitoring::TDynamicCounters::TCounterPtr InFlight6;
NMonitoring::TDynamicCounters::TCounterPtr InFlight4;
+ NMonitoring::TDynamicCounters::TCounterPtr TotalUnspec;
NMonitoring::TDynamicCounters::TCounterPtr Total6;
NMonitoring::TDynamicCounters::TCounterPtr Total4;
NMonitoring::TDynamicCounters::TCounterPtr Misses;
@@ -175,6 +189,7 @@ Y_UNIT_TEST_SUITE(CachingDnsResolver) {
THashMap<TString, TMockReply> ReplyV6;
THashMap<TString, TMockReply> ReplyV4;
+ THashMap<TString, TMockReply> ReplyUnspec;
TCachingDnsRuntime() {
SetScheduledEventFilter([](auto&&, auto&&, auto&&, auto&&) { return false; });
@@ -186,6 +201,9 @@ Y_UNIT_TEST_SUITE(CachingDnsResolver) {
ReplyV4["yandex.ru"] = TMockReply::SingleV4("77.88.55.77", TDuration::MilliSeconds(250));
ReplyV6["router.asus.com"] = TMockReply::Error(ARES_ENODATA);
ReplyV4["router.asus.com"] = TMockReply::SingleV4("192.168.0.1");
+ ReplyUnspec["localhost"] = ReplyV6.at("localhost") + ReplyV4.at("localhost");
+ ReplyUnspec["yandex.ru"] = ReplyV6.at("yandex.ru") + ReplyV4.at("yandex.ru");
+ ReplyUnspec["router.asus.com"] = ReplyV4.at("router.asus.com");
}
void Start(TMockDnsCallback callback) {
@@ -194,8 +212,10 @@ Y_UNIT_TEST_SUITE(CachingDnsResolver) {
Resolver = Register(CreateCachingDnsResolver(MockResolver, ResolverOptions));
Sleeper = AllocateEdgeActor();
+ InFlightUnspec = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/InFlight/Unspec", false);
InFlight6 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/InFlight/V6", false);
InFlight4 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/InFlight/V4", false);
+ TotalUnspec = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/Total/Unspec", true);
Total6 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/Total/V6", true);
Total4 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/Total/V4", true);
Misses = ResolverOptions.MonCounters->GetCounter("DnsResolver/Cache/Misses", true);
@@ -205,6 +225,13 @@ Y_UNIT_TEST_SUITE(CachingDnsResolver) {
void Start() {
Start([this](const TString& name, int family) {
switch (family) {
+ case AF_UNSPEC: {
+ auto it = ReplyUnspec.find(name);
+ if (it != ReplyUnspec.end()) {
+ return it->second;
+ }
+ break;
+ }
case AF_INET6: {
auto it = ReplyV6.find(name);
if (it != ReplyV6.end()) {
@@ -234,10 +261,10 @@ Y_UNIT_TEST_SUITE(CachingDnsResolver) {
}
void WaitNoInFlight() {
- if (*InFlight6 || *InFlight4) {
+ if (*InFlightUnspec || *InFlight6 || *InFlight4) {
TDispatchOptions options;
options.CustomFinalCondition = [&]() {
- return !*InFlight6 && !*InFlight4;
+ return !*InFlightUnspec && !*InFlight6 && !*InFlight4;
};
DispatchEvents(options);
UNIT_ASSERT_C(!*InFlight6 && !*InFlight4, "Failed to wait for no inflight in " << Section_);
@@ -260,6 +287,10 @@ Y_UNIT_TEST_SUITE(CachingDnsResolver) {
return GrabEdgeEventRethrow<TEvDns::TEvGetAddrResult>(sender);
}
+ void ExpectInFlightUnspec(i64 count) {
+ UNIT_ASSERT_VALUES_EQUAL_C(InFlightUnspec->Val(), count, Section_);
+ }
+
void ExpectInFlight6(i64 count) {
UNIT_ASSERT_VALUES_EQUAL_C(InFlight6->Val(), count, Section_);
}
@@ -268,6 +299,10 @@ Y_UNIT_TEST_SUITE(CachingDnsResolver) {
UNIT_ASSERT_VALUES_EQUAL_C(InFlight4->Val(), count, Section_);
}
+ void ExpectTotalUnspec(i64 count) {
+ UNIT_ASSERT_VALUES_EQUAL_C(TotalUnspec->Val(), count, Section_);
+ }
+
void ExpectTotal6(i64 count) {
UNIT_ASSERT_VALUES_EQUAL_C(Total6->Val(), count, Section_);
}
@@ -276,6 +311,13 @@ Y_UNIT_TEST_SUITE(CachingDnsResolver) {
UNIT_ASSERT_VALUES_EQUAL_C(Total4->Val(), count, Section_);
}
+ void ExpectUnspec(i64 total, i64 inflight) {
+ UNIT_ASSERT_C(
+ TotalUnspec->Val() == total && InFlightUnspec->Val() == inflight,
+ Section_ << ": Expect6(" << total << ", " << inflight << ") "
+ << " but got (" << TotalUnspec->Val() << ", " << InFlightUnspec->Val() << ")");
+ }
+
void Expect6(i64 total, i64 inflight) {
UNIT_ASSERT_C(
Total6->Val() == total && InFlight6->Val() == inflight,
@@ -357,61 +399,41 @@ Y_UNIT_TEST_SUITE(CachingDnsResolver) {
auto sender = runtime.AllocateEdgeActor();
- // First time resolve, ipv4 and ipv6 sent in parallel, we wait for ipv6 result
+ // First time resolve, we expect AF_UNSPEC result to be cached
runtime.Section("First time resolve");
runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
- runtime.Expect6(1, 0);
- runtime.Expect4(1, 0);
+ runtime.ExpectUnspec(1, 0);
runtime.ExpectMisses(1);
runtime.ExpectHits(0);
- // Second resolve, ipv6 and ipv4 queries result in a cache hit
- runtime.Section("Second resolve, ipv6");
- runtime.SendGetAddr(sender, "yandex.ru", AF_INET6);
+ // Second resolve, unspec is a cache hit, ipv6 and ipv4 result in cache misses
+ runtime.Section("Second resolve");
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
- runtime.Expect6(1, 0);
+ runtime.ExpectUnspec(1, 0);
runtime.ExpectHits(1);
- runtime.Section("Second resolve, ipv4");
- runtime.SendGetAddr(sender, "yandex.ru", AF_INET);
- runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
- runtime.Expect4(1, 0);
- runtime.ExpectHits(2);
- // Wait until soft expiration and try ipv4 again
- // Will cause a cache hit, but will start a new ipv4 request in background
- runtime.Section("Retry ipv4 after soft expiration");
- runtime.Sleep(TDuration::Seconds(15));
- runtime.SendGetAddr(sender, "yandex.ru", AF_INET);
- runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
- runtime.Expect6(1, 0);
- runtime.Expect4(2, 1);
- runtime.ExpectMisses(1);
- runtime.ExpectHits(3);
- runtime.WaitNoInFlight();
-
- // Wait until soft expiration and try both again
- // Will cause a cache hit, but will start a new ipv6 request in background
+ // Wait until soft expiration and try unspec again
+ // Will cause a cache hit, but will start a new request in background
runtime.Section("Retry both after soft expiration");
runtime.Sleep(TDuration::Seconds(15));
runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
- runtime.Expect6(2, 1);
- runtime.Expect4(2, 0);
+ runtime.ExpectUnspec(2, 1);
runtime.ExpectMisses(1);
- runtime.ExpectHits(4);
+ runtime.ExpectHits(2);
runtime.WaitNoInFlight();
- // Wait until hard expiration and try both again
+ // Wait until hard expiration and try unspec again
// Will cause a cache miss and new resolve requests
runtime.Section("Retry both after hard expiration");
runtime.Sleep(TDuration::Hours(2));
runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
- runtime.Expect6(3, 0);
- runtime.Expect4(3, 0);
+ runtime.ExpectUnspec(3, 0);
runtime.ExpectMisses(2);
- runtime.ExpectHits(4);
+ runtime.ExpectHits(2);
// Wait half the hard expiration time, must always result in a cache hit
runtime.Section("Retry both after half hard expiration");
@@ -419,39 +441,38 @@ Y_UNIT_TEST_SUITE(CachingDnsResolver) {
runtime.Sleep(TDuration::Hours(1));
runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
- runtime.Expect6(3 + i, 1);
- runtime.ExpectHits(4 + i);
+ runtime.ExpectUnspec(3 + i, 1);
+ runtime.ExpectHits(2 + i);
runtime.WaitNoInFlight();
}
- // Change v6 result to a timeout, must keep using cached result until hard expiration
+ // Change unspec result to a timeout, must keep using cached result until hard expiration
runtime.Section("Dns keeps timing out");
- runtime.ReplyV6["yandex.ru"] = TMockReply::Error(ARES_ETIMEOUT);
+ runtime.ReplyUnspec["yandex.ru"] = TMockReply::Error(ARES_ETIMEOUT);
for (ui64 i = 1; i <= 4; ++i) {
runtime.Sleep(TDuration::Seconds(15));
runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
- runtime.Expect6(7 + i, 1);
- runtime.ExpectHits(8 + i);
+ runtime.ExpectUnspec(7 + i, 1);
+ runtime.ExpectHits(6 + i);
runtime.WaitNoInFlight();
}
- // Change v6 result to nodata, must switch to a v4 result eventually
+ // Change unspec result to v4, must switch to a v4 result eventually
runtime.Section("Host changes to being ipv4 only");
- runtime.ReplyV6["yandex.ru"] = TMockReply::Error(ARES_ENODATA);
+ runtime.ReplyUnspec["yandex.ru"] = runtime.ReplyV4.at("yandex.ru");
runtime.Sleep(TDuration::Seconds(2));
runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
runtime.WaitNoInFlight();
runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
- runtime.Expect6(12, 0);
- runtime.Expect4(4, 0);
- runtime.ExpectMisses(3);
+ runtime.ExpectUnspec(12, 0);
+ runtime.ExpectMisses(2);
- // Change v6 result to nxdomain, must not fall back to a v4 result
+ // Change unspec result to nxdomain, must start returning it
runtime.Section("Host is removed from dns");
- runtime.ReplyV6["yandex.ru"] = TMockReply::Error(ARES_ENOTFOUND);
+ runtime.ReplyUnspec["yandex.ru"] = TMockReply::Error(ARES_ENOTFOUND);
runtime.Sleep(TDuration::Seconds(15));
runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
@@ -478,20 +499,18 @@ Y_UNIT_TEST_SUITE(CachingDnsResolver) {
runtime.ExpectHits(1);
runtime.Section("Dns keeps timing out");
- runtime.ReplyV6["router.asus.com"] = TMockReply::Error(ARES_ETIMEOUT);
- runtime.ReplyV4["router.asus.com"] = TMockReply::Error(ARES_ETIMEOUT);
+ runtime.ReplyUnspec["router.asus.com"] = TMockReply::Error(ARES_ETIMEOUT);
for (ui64 i = 1; i <= 4; ++i) {
runtime.Sleep(TDuration::Seconds(15));
runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
- runtime.Expect6(1 + i, 1);
- runtime.Expect4(1 + i, 1);
+ runtime.ExpectUnspec(1 + i, 1);
runtime.ExpectHits(1 + i);
runtime.WaitNoInFlight();
}
- runtime.Section("Host is removed from ipv4 dns");
- runtime.ReplyV4["router.asus.com"] = TMockReply::Error(ARES_ENOTFOUND);
+ runtime.Section("Host is removed from dns");
+ runtime.ReplyUnspec["router.asus.com"] = TMockReply::Error(ARES_ENOTFOUND);
runtime.Sleep(TDuration::Seconds(15));
runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
@@ -507,12 +526,11 @@ Y_UNIT_TEST_SUITE(CachingDnsResolver) {
auto sender = runtime.AllocateEdgeActor();
- runtime.ReplyV6["notfound.ru"] = TMockReply::Error(ARES_ENODATA);
- runtime.ReplyV4["notfound.ru"] = TMockReply::Error(ARES_ENOTFOUND);
+ runtime.ReplyUnspec["notfound.ru"] = TMockReply::Error(ARES_ENOTFOUND);
runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
- runtime.ReplyV4["notfound.ru"] = TMockReply::Error(ARES_ETIMEOUT);
+ runtime.ReplyUnspec["notfound.ru"] = TMockReply::Error(ARES_ETIMEOUT);
runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
runtime.WaitNoInFlight();
@@ -546,7 +564,7 @@ Y_UNIT_TEST_SUITE(CachingDnsResolver) {
runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
runtime.ExpectGetHostByNameSuccess(sender, "192.168.0.1");
runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
- runtime.ExpectGetHostByNameSuccess(sender, "2a02:6b8:a::a");
+ runtime.ExpectGetHostByNameSuccess(sender, "2a02:6b8:a::a,77.88.55.77");
runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
runtime.SendGetHostByName(sender, "notfound.ru", AF_UNSPEC);
diff --git a/library/cpp/actors/interconnect/events_local.h b/library/cpp/actors/interconnect/events_local.h
index 8a46ffd535..233ca812fe 100644
--- a/library/cpp/actors/interconnect/events_local.h
+++ b/library/cpp/actors/interconnect/events_local.h
@@ -239,7 +239,7 @@ namespace NActors {
DEFINE_SIMPLE_LOCAL_EVENT(TEvLocalNodeInfo, "Network: TEvLocalNodeInfo")
ui32 NodeId;
- NAddr::IRemoteAddrPtr Address;
+ std::vector<NInterconnect::TAddress> Addresses;
};
struct TEvBunchOfEventsToDestroy : TEventLocal<TEvBunchOfEventsToDestroy, ui32(ENetwork::BunchOfEventsToDestroy)> {
diff --git a/library/cpp/actors/interconnect/interconnect_address.cpp b/library/cpp/actors/interconnect/interconnect_address.cpp
index 8f474f5a39..ac647f8263 100644
--- a/library/cpp/actors/interconnect/interconnect_address.cpp
+++ b/library/cpp/actors/interconnect/interconnect_address.cpp
@@ -70,6 +70,18 @@ namespace NInterconnect {
: TAddress(addr.data(), port)
{}
+ TAddress::TAddress(in_addr addr, ui16 port) {
+ Addr.Ipv4.sin_family = AF_INET;
+ Addr.Ipv4.sin_port = htons(port);
+ Addr.Ipv4.sin_addr = addr;
+ }
+
+ TAddress::TAddress(in6_addr addr, ui16 port) {
+ Addr.Ipv6.sin6_family = AF_INET6;
+ Addr.Ipv6.sin6_port = htons(port);
+ Addr.Ipv6.sin6_addr = addr;
+ }
+
TString TAddress::GetAddress() const {
const void *src;
socklen_t size;
diff --git a/library/cpp/actors/interconnect/interconnect_address.h b/library/cpp/actors/interconnect/interconnect_address.h
index 5a78193abb..b19d751806 100644
--- a/library/cpp/actors/interconnect/interconnect_address.h
+++ b/library/cpp/actors/interconnect/interconnect_address.h
@@ -17,6 +17,8 @@ namespace NInterconnect {
TAddress();
TAddress(const char* addr, ui16 port);
TAddress(const TString& addr, ui16 port);
+ TAddress(in_addr addr, ui16 port);
+ TAddress(in6_addr addr, ui16 port);
TAddress(NAddr::IRemoteAddr& addr);
int GetFamily() const;
socklen_t Size() const;
diff --git a/library/cpp/actors/interconnect/interconnect_handshake.cpp b/library/cpp/actors/interconnect/interconnect_handshake.cpp
index 9ede998d8e..aecb369866 100644
--- a/library/cpp/actors/interconnect/interconnect_handshake.cpp
+++ b/library/cpp/actors/interconnect/interconnect_handshake.cpp
@@ -828,59 +828,67 @@ namespace NActors {
Now() + ResolveTimeout);
// extract address from the result
- NInterconnect::TAddress address;
+ std::vector<NInterconnect::TAddress> addresses;
if (!ev) {
ResolveTimedOut = true;
if (auto peerNodeInfo = GetPeerNodeInfo(); peerNodeInfo && peerNodeInfo->Address) {
- address = {peerNodeInfo->Address, peerNodeInfo->Port};
+ addresses.emplace_back(peerNodeInfo->Address, peerNodeInfo->Port);
} else {
Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve timed out and no static address defined", true);
}
} else if (auto *p = ev->CastAsLocal<TEvLocalNodeInfo>()) {
- if (!p->Address) {
+ addresses = std::move(p->Addresses);
+ if (addresses.empty()) {
Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve error: no address returned", true);
}
- address = {*p->Address};
} else if (auto *p = ev->CastAsLocal<TEvInterconnect::TEvNodeAddress>()) {
const auto& r = p->Record;
if (!r.HasAddress() || !r.HasPort()) {
Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve error: no address returned", true);
}
- address = {r.GetAddress(), static_cast<ui16>(r.GetPort())};
+ addresses.emplace_back(r.GetAddress(), static_cast<ui16>(r.GetPort()));
} else {
Y_VERIFY(ev->GetTypeRewrite() == ui32(ENetwork::ResolveError));
Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve error: " + ev->Get<TEvResolveError>()->Explain, true);
}
- // create the socket with matching address family
- Socket = NInterconnect::TStreamSocket::Make(address.GetFamily());
- if (*Socket == -1) {
- Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "System error: failed to create socket");
- }
-
- // extract peer address
- if (updatePeerAddr) {
- PeerAddr = address.ToString();
- }
+ for (const NInterconnect::TAddress& address : addresses) {
+ // create the socket with matching address family
+ int err = 0;
+ Socket = NInterconnect::TStreamSocket::Make(address.GetFamily(), &err);
+ if (err == EAFNOSUPPORT) {
+ Socket.Reset();
+ continue;
+ } else if (*Socket == -1) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "System error: failed to create socket");
+ }
- // set up socket parameters
- SetupSocket();
+ // extract peer address
+ if (updatePeerAddr) {
+ PeerAddr = address.ToString();
+ }
- // start connecting
- switch (int err = -Socket->Connect(address)) {
- case 0: // successful connection
- break;
+ // set up socket parameters
+ SetupSocket();
- case EINPROGRESS: // connection in progress
+ // start connecting
+ err = -Socket->Connect(address);
+ if (err == EINPROGRESS) {
WaitPoller(false, true, "WaitConnect");
err = Socket->GetConnectStatus();
- if (err) {
- Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, Sprintf("Connection failed: %s", strerror(err)), true);
- }
- break;
+ }
- default:
+ // check if connection succeeded
+ if (err) {
+ Socket.Reset();
+ PollerToken.Reset();
+ } else {
break;
+ }
+ }
+
+ if (!Socket) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "Couldn't connect to any resolved address", true);
}
auto it = LastLogNotice.find(PeerNodeId);
diff --git a/library/cpp/actors/interconnect/interconnect_resolve.cpp b/library/cpp/actors/interconnect/interconnect_resolve.cpp
index 14296194df..502de446c7 100644
--- a/library/cpp/actors/interconnect/interconnect_resolve.cpp
+++ b/library/cpp/actors/interconnect/interconnect_resolve.cpp
@@ -41,7 +41,11 @@ namespace NActors {
void Bootstrap() {
TMaybe<TString> errorText;
if (auto addr = ExtractDefaultAddr(errorText)) {
- return SendAddrAndDie(std::move(addr));
+ if (NodeId) {
+ return SendLocalNodeInfoAndDie({{*addr}});
+ } else {
+ return SendAddressInfoAndDie(std::move(addr));
+ }
}
if (errorText) {
@@ -55,8 +59,10 @@ namespace NActors {
}
Send(MakeDnsResolverActorId(),
- new TEvDns::TEvGetAddr(Host, AF_UNSPEC),
- IEventHandle::FlagTrackDelivery);
+ NodeId
+ ? static_cast<IEventBase*>(new TEvDns::TEvGetHostByName(Host, AF_UNSPEC))
+ : static_cast<IEventBase*>(new TEvDns::TEvGetAddr(Host, AF_UNSPEC)),
+ IEventHandle::FlagTrackDelivery);
if (Deadline != TInstant::Max()) {
Schedule(Deadline, new TEvents::TEvWakeup);
@@ -69,6 +75,7 @@ namespace NActors {
sFunc(TEvents::TEvWakeup, HandleTimeout);
sFunc(TEvents::TEvUndelivered, HandleUndelivered);
hFunc(TEvDns::TEvGetAddrResult, Handle);
+ hFunc(TEvDns::TEvGetHostByNameResult, Handle);
});
void HandleTimeout() {
@@ -81,23 +88,40 @@ namespace NActors {
void Handle(TEvDns::TEvGetAddrResult::TPtr& ev) {
if (auto addr = ExtractAddr(ev->Get())) {
- return SendAddrAndDie(std::move(addr));
+ SendAddressInfoAndDie(std::move(addr));
+ } else {
+ SendErrorAndDie(ev->Get()->ErrorText);
}
-
- SendErrorAndDie(ev->Get()->ErrorText);
}
- void SendAddrAndDie(NAddr::IRemoteAddrPtr addr) {
- if (NodeId) {
- auto reply = new TEvLocalNodeInfo;
- reply->NodeId = *NodeId;
- reply->Address = std::move(addr);
- TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, reply));
+ void Handle(TEvDns::TEvGetHostByNameResult::TPtr& ev) {
+ auto& msg = *ev->Get();
+ if (msg.Status) {
+ SendErrorAndDie(msg.ErrorText);
} else {
- auto reply = new TEvAddressInfo;
- reply->Address = std::move(addr);
- TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, reply));
+ std::vector<NInterconnect::TAddress> addresses;
+ for (const auto& ipv6 : msg.AddrsV6) {
+ addresses.emplace_back(ipv6, Port);
+ }
+ for (const auto& ipv4 : msg.AddrsV4) {
+ addresses.emplace_back(ipv4, Port);
+ }
+ SendLocalNodeInfoAndDie(std::move(addresses));
}
+ }
+
+ void SendAddressInfoAndDie(NAddr::IRemoteAddrPtr addr) {
+ auto reply = new TEvAddressInfo;
+ reply->Address = std::move(addr);
+ TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, reply));
+ PassAway();
+ }
+
+ void SendLocalNodeInfoAndDie(std::vector<NInterconnect::TAddress> addresses) {
+ auto reply = std::make_unique<TEvLocalNodeInfo>();
+ reply->NodeId = *NodeId;
+ reply->Addresses = std::move(addresses);
+ TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, reply.release()));
PassAway();
}