diff options
author | Daniil Cherednik <dan.cherednik@gmail.com> | 2022-07-06 23:04:30 +0300 |
---|---|---|
committer | Daniil Cherednik <dan.cherednik@gmail.com> | 2022-07-06 23:04:30 +0300 |
commit | 8b2fafa9888f6a85ad33912eccfb691f037fb285 (patch) | |
tree | 7beb62227739d1083b43993da45bf7e06810ebbd | |
parent | 08f543ac96eec65f35893e17a19dd1a10266b9d1 (diff) | |
download | ydb-8b2fafa9888f6a85ad33912eccfb691f037fb285.tar.gz |
Missed changes for 33e0b0f01d29fe0a000c45feea0d5c855e0e78ae
x-ydb-stable-ref: b5a1b56ccae72d0629280e8a1247f041f9c72ce7
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(); } |