diff options
author | bulatman <bulatman@yandex-team.ru> | 2022-02-10 16:45:50 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:50 +0300 |
commit | 6560e4993b14d193f8c879e33a3de5e5eba6e21d (patch) | |
tree | cfd2e2baa05c3196f2caacbb63c32e1df40bc3de /library/cpp/testing/common/network.cpp | |
parent | 7489e4682331202b9c7d863c0898eb83d7b12c2b (diff) | |
download | ydb-6560e4993b14d193f8c879e33a3de5e5eba6e21d.tar.gz |
Restoring authorship annotation for <bulatman@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'library/cpp/testing/common/network.cpp')
-rw-r--r-- | library/cpp/testing/common/network.cpp | 406 |
1 files changed, 203 insertions, 203 deletions
diff --git a/library/cpp/testing/common/network.cpp b/library/cpp/testing/common/network.cpp index 230c50ee6d..b06670b8d0 100644 --- a/library/cpp/testing/common/network.cpp +++ b/library/cpp/testing/common/network.cpp @@ -1,208 +1,208 @@ -#include "network.h" - -#include <util/folder/dirut.h> -#include <util/folder/path.h> -#include <util/generic/singleton.h> -#include <util/generic/utility.h> -#include <util/generic/vector.h> -#include <util/generic/ylimits.h> -#include <util/network/address.h> -#include <util/network/sock.h> -#include <util/random/random.h> -#include <util/stream/file.h> -#include <util/string/split.h> -#include <util/system/env.h> -#include <util/system/error.h> -#include <util/system/file_lock.h> -#include <util/system/fs.h> - -#ifdef _darwin_ -#include <sys/types.h> -#include <sys/sysctl.h> -#endif - -namespace { -#define Y_VERIFY_SYSERROR(expr) \ - do { \ - if (!(expr)) { \ - Y_FAIL(#expr ", errno=%d", LastSystemError()); \ - } \ - } while (false) - - class TPortGuard : public NTesting::IPort { - public: - TPortGuard(ui16 port, THolder<TFileLock> lock) - : Lock_(std::move(lock)) - , Port_(port) - { - } - +#include "network.h" + +#include <util/folder/dirut.h> +#include <util/folder/path.h> +#include <util/generic/singleton.h> +#include <util/generic/utility.h> +#include <util/generic/vector.h> +#include <util/generic/ylimits.h> +#include <util/network/address.h> +#include <util/network/sock.h> +#include <util/random/random.h> +#include <util/stream/file.h> +#include <util/string/split.h> +#include <util/system/env.h> +#include <util/system/error.h> +#include <util/system/file_lock.h> +#include <util/system/fs.h> + +#ifdef _darwin_ +#include <sys/types.h> +#include <sys/sysctl.h> +#endif + +namespace { +#define Y_VERIFY_SYSERROR(expr) \ + do { \ + if (!(expr)) { \ + Y_FAIL(#expr ", errno=%d", LastSystemError()); \ + } \ + } while (false) + + class TPortGuard : public NTesting::IPort { + public: + TPortGuard(ui16 port, THolder<TFileLock> lock) + : Lock_(std::move(lock)) + , Port_(port) + { + } + ~TPortGuard() override { - Y_VERIFY_SYSERROR(NFs::Remove(Lock_->GetName())); - } - - ui16 Get() override { - return Port_; - } - - private: - THolder<TFileLock> Lock_; - ui16 Port_; - }; - - std::pair<ui16, ui16> GetEphemeralRange() { - // IANA suggestion - std::pair<ui16, ui16> pair{(1 << 15) + (1 << 14), (1 << 16) - 1}; - #ifdef _linux_ - if (NFs::Exists("/proc/sys/net/ipv4/ip_local_port_range")) { - TIFStream fileStream("/proc/sys/net/ipv4/ip_local_port_range"); - fileStream >> pair.first >> pair.second; - } - #endif - #ifdef _darwin_ - ui32 first, last; - size_t size; - sysctlbyname("net.inet.ip.portrange.first", &first, &size, NULL, 0); - sysctlbyname("net.inet.ip.portrange.last", &last, &size, NULL, 0); - pair.first = first; - pair.second = last; - #endif - return pair; - } - - TVector<std::pair<ui16, ui16>> GetPortRanges() { - TString givenRange = GetEnv("VALID_PORT_RANGE"); - TVector<std::pair<ui16, ui16>> ranges; - if (givenRange.Contains(':')) { - auto res = StringSplitter(givenRange).Split(':').Limit(2).ToList<TString>(); - ranges.emplace_back(FromString<ui16>(res.front()), FromString<ui16>(res.back())); - } else { - const ui16 firstValid = 1025; - const ui16 lastValid = Max<ui16>(); - - auto [firstEphemeral, lastEphemeral] = GetEphemeralRange(); - const ui16 firstInvalid = Max(firstEphemeral, firstValid); - const ui16 lastInvalid = Min(lastEphemeral, lastValid); - - if (firstInvalid > firstValid) - ranges.emplace_back(firstValid, firstInvalid - 1); - if (lastInvalid < lastValid) - ranges.emplace_back(lastInvalid + 1, lastValid); - } - return ranges; - } - - class TPortManager { - static constexpr size_t Retries = 20; - public: - TPortManager() - : SyncDir_(GetEnv("PORT_SYNC_PATH")) - , Ranges_(GetPortRanges()) - , TotalCount_(0) - { - if (!SyncDir_.IsDefined()) { - SyncDir_ = TFsPath(GetSystemTempDir()) / "yandex_port_locks"; - } - Y_VERIFY(SyncDir_.IsDefined()); - NFs::MakeDirectoryRecursive(SyncDir_); - - for (auto [left, right] : Ranges_) { - TotalCount_ += right - left; - } - Y_VERIFY(0 != TotalCount_); - } - - NTesting::TPortHolder GetFreePort() const { - ui16 salt = RandomNumber<ui16>(); - for (ui16 attempt = 0; attempt < TotalCount_; ++attempt) { - ui16 probe = (salt + attempt) % TotalCount_; - - for (auto [left, right] : Ranges_) { - if (probe >= right - left) - probe -= right - left; - else { - probe += left; - break; - } - } - - auto port = TryAcquirePort(probe); - if (port) { - return NTesting::TPortHolder{std::move(port)}; - } - } - - Y_FAIL("Cannot get free port!"); - } - - TVector<NTesting::TPortHolder> GetFreePortsRange(size_t count) const { - Y_VERIFY(count > 0); - TVector<NTesting::TPortHolder> ports(Reserve(count)); - for (size_t i = 0; i < Retries; ++i) { - for (auto[left, right] : Ranges_) { - if (right - left < count) { - continue; - } - ui16 start = left + RandomNumber<ui16>((right - left) / 2); - if (right - start < count) { - continue; - } - for (ui16 probe = start; probe < right; ++probe) { - auto port = TryAcquirePort(probe); - if (port) { - ports.emplace_back(std::move(port)); - } else { - ports.clear(); - } - if (ports.size() == count) { - return ports; - } - } - // Can't find required number of ports without gap in the current range - ports.clear(); - } - } - Y_FAIL("Cannot get range of %zu ports!", count); - } - - private: - THolder<NTesting::IPort> TryAcquirePort(ui16 port) const { - auto lock = MakeHolder<TFileLock>(TString(SyncDir_ / ::ToString(port))); - if (!lock->TryAcquire()) { - return nullptr; - } - - TInet6StreamSocket sock; - Y_VERIFY_SYSERROR(INVALID_SOCKET != static_cast<SOCKET>(sock)); - - TSockAddrInet6 addr("::", port); - if (sock.Bind(&addr) != 0) { - lock->Release(); - Y_VERIFY(EADDRINUSE == LastSystemError(), "unexpected error: %d", LastSystemError()); - return nullptr; - } - return MakeHolder<TPortGuard>(port, std::move(lock)); - } - - private: - TFsPath SyncDir_; - TVector<std::pair<ui16, ui16>> Ranges_; - size_t TotalCount_; - }; -} - -namespace NTesting { - TPortHolder GetFreePort() { - return Singleton<TPortManager>()->GetFreePort(); - } - - namespace NLegacy { - TVector<TPortHolder> GetFreePortsRange(size_t count) { - return Singleton<TPortManager>()->GetFreePortsRange(count); - } - } + Y_VERIFY_SYSERROR(NFs::Remove(Lock_->GetName())); + } + + ui16 Get() override { + return Port_; + } + + private: + THolder<TFileLock> Lock_; + ui16 Port_; + }; + + std::pair<ui16, ui16> GetEphemeralRange() { + // IANA suggestion + std::pair<ui16, ui16> pair{(1 << 15) + (1 << 14), (1 << 16) - 1}; + #ifdef _linux_ + if (NFs::Exists("/proc/sys/net/ipv4/ip_local_port_range")) { + TIFStream fileStream("/proc/sys/net/ipv4/ip_local_port_range"); + fileStream >> pair.first >> pair.second; + } + #endif + #ifdef _darwin_ + ui32 first, last; + size_t size; + sysctlbyname("net.inet.ip.portrange.first", &first, &size, NULL, 0); + sysctlbyname("net.inet.ip.portrange.last", &last, &size, NULL, 0); + pair.first = first; + pair.second = last; + #endif + return pair; + } + + TVector<std::pair<ui16, ui16>> GetPortRanges() { + TString givenRange = GetEnv("VALID_PORT_RANGE"); + TVector<std::pair<ui16, ui16>> ranges; + if (givenRange.Contains(':')) { + auto res = StringSplitter(givenRange).Split(':').Limit(2).ToList<TString>(); + ranges.emplace_back(FromString<ui16>(res.front()), FromString<ui16>(res.back())); + } else { + const ui16 firstValid = 1025; + const ui16 lastValid = Max<ui16>(); + + auto [firstEphemeral, lastEphemeral] = GetEphemeralRange(); + const ui16 firstInvalid = Max(firstEphemeral, firstValid); + const ui16 lastInvalid = Min(lastEphemeral, lastValid); + + if (firstInvalid > firstValid) + ranges.emplace_back(firstValid, firstInvalid - 1); + if (lastInvalid < lastValid) + ranges.emplace_back(lastInvalid + 1, lastValid); + } + return ranges; + } + + class TPortManager { + static constexpr size_t Retries = 20; + public: + TPortManager() + : SyncDir_(GetEnv("PORT_SYNC_PATH")) + , Ranges_(GetPortRanges()) + , TotalCount_(0) + { + if (!SyncDir_.IsDefined()) { + SyncDir_ = TFsPath(GetSystemTempDir()) / "yandex_port_locks"; + } + Y_VERIFY(SyncDir_.IsDefined()); + NFs::MakeDirectoryRecursive(SyncDir_); + + for (auto [left, right] : Ranges_) { + TotalCount_ += right - left; + } + Y_VERIFY(0 != TotalCount_); + } + + NTesting::TPortHolder GetFreePort() const { + ui16 salt = RandomNumber<ui16>(); + for (ui16 attempt = 0; attempt < TotalCount_; ++attempt) { + ui16 probe = (salt + attempt) % TotalCount_; + + for (auto [left, right] : Ranges_) { + if (probe >= right - left) + probe -= right - left; + else { + probe += left; + break; + } + } + + auto port = TryAcquirePort(probe); + if (port) { + return NTesting::TPortHolder{std::move(port)}; + } + } + + Y_FAIL("Cannot get free port!"); + } + + TVector<NTesting::TPortHolder> GetFreePortsRange(size_t count) const { + Y_VERIFY(count > 0); + TVector<NTesting::TPortHolder> ports(Reserve(count)); + for (size_t i = 0; i < Retries; ++i) { + for (auto[left, right] : Ranges_) { + if (right - left < count) { + continue; + } + ui16 start = left + RandomNumber<ui16>((right - left) / 2); + if (right - start < count) { + continue; + } + for (ui16 probe = start; probe < right; ++probe) { + auto port = TryAcquirePort(probe); + if (port) { + ports.emplace_back(std::move(port)); + } else { + ports.clear(); + } + if (ports.size() == count) { + return ports; + } + } + // Can't find required number of ports without gap in the current range + ports.clear(); + } + } + Y_FAIL("Cannot get range of %zu ports!", count); + } + + private: + THolder<NTesting::IPort> TryAcquirePort(ui16 port) const { + auto lock = MakeHolder<TFileLock>(TString(SyncDir_ / ::ToString(port))); + if (!lock->TryAcquire()) { + return nullptr; + } + + TInet6StreamSocket sock; + Y_VERIFY_SYSERROR(INVALID_SOCKET != static_cast<SOCKET>(sock)); + + TSockAddrInet6 addr("::", port); + if (sock.Bind(&addr) != 0) { + lock->Release(); + Y_VERIFY(EADDRINUSE == LastSystemError(), "unexpected error: %d", LastSystemError()); + return nullptr; + } + return MakeHolder<TPortGuard>(port, std::move(lock)); + } + + private: + TFsPath SyncDir_; + TVector<std::pair<ui16, ui16>> Ranges_; + size_t TotalCount_; + }; +} + +namespace NTesting { + TPortHolder GetFreePort() { + return Singleton<TPortManager>()->GetFreePort(); + } + + namespace NLegacy { + TVector<TPortHolder> GetFreePortsRange(size_t count) { + return Singleton<TPortManager>()->GetFreePortsRange(count); + } + } IOutputStream& operator<<(IOutputStream& out, const TPortHolder& port) { return out << static_cast<ui16>(port); } -} +} |