From 45bf00b8a6ee2e08aa2418e3022b396439e7b070 Mon Sep 17 00:00:00 2001 From: Corey Kosak Date: Wed, 24 Jul 2024 22:05:16 -0400 Subject: [PATCH] feat(cpp-client): Move GetHostname and GetEnv to dhcore (#5845) --- .../public/deephaven/dhcore/utility/utility.h | 14 ++++ .../src/utility/utility_platform_specific.cc | 73 ++++++++++++++++++- .../deephaven/tests/src/utility_test.cc | 25 ++++++- 3 files changed, 107 insertions(+), 5 deletions(-) diff --git a/cpp-client/deephaven/dhcore/include/public/deephaven/dhcore/utility/utility.h b/cpp-client/deephaven/dhcore/include/public/deephaven/dhcore/utility/utility.h index 354c3d18fbe..29913011f39 100644 --- a/cpp-client/deephaven/dhcore/include/public/deephaven/dhcore/utility/utility.h +++ b/cpp-client/deephaven/dhcore/include/public/deephaven/dhcore/utility/utility.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -203,6 +204,19 @@ std::string Basename(std::string_view path); */ [[nodiscard]] std::string GetTidAsString(); +/** + * Gets the hostname. + * @return The hostname. + */ +[[nodiscard]] std::string GetHostname(); + +/** + * Gets a value from the environment. + * @param envname the key + * @return If found, an optional set to the value. Otherwise (if not found), an empty optional. + */ +[[nodiscard]] std::optional GetEnv(const std::string& envname); + template [[nodiscard]] std::string TypeName(const T& t) { return demangle(typeid(t).name()); diff --git a/cpp-client/deephaven/dhcore/src/utility/utility_platform_specific.cc b/cpp-client/deephaven/dhcore/src/utility/utility_platform_specific.cc index 35e75d6c9d0..5a834efe04d 100644 --- a/cpp-client/deephaven/dhcore/src/utility/utility_platform_specific.cc +++ b/cpp-client/deephaven/dhcore/src/utility/utility_platform_specific.cc @@ -1,27 +1,92 @@ /* * Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending */ +#include +#include #include #include "deephaven/dhcore/utility/utility.h" -// for GetTidAsString -#if defined(__linux__) +#if defined(__unix__) +#include #include #include +#include #elif defined(_WIN32) #include +#include "winsock.h" #endif namespace deephaven::dhcore::utility { -[[nodiscard]] std::string GetTidAsString() { +std::string GetTidAsString() { #if defined(__linux__) const pid_t tid = syscall(__NR_gettid); // this is more portable than gettid(). return std::to_string(tid); #elif defined(_WIN32) auto tid = GetCurrentThreadId(); -return std::to_string(tid); + return std::to_string(tid); #else #error "Don't have a way to getting thread id on your platform" #endif } + +std::string GetHostname() { +#if defined(__unix__) + char hostname[HOST_NAME_MAX]; + gethostname(hostname, HOST_NAME_MAX); + const addrinfo hints = { AI_ADDRCONFIG|AI_CANONNAME, AF_UNSPEC, 0, 0 }; + addrinfo *info; + const int r = getaddrinfo(hostname, nullptr, &hints, &info); + if (r != 0 || info == nullptr) { + throw std::runtime_error(DEEPHAVEN_LOCATION_STR("getaddrinfo failed: ") + gai_strerror(r)); + } + // Of all the alternatives, pick the longest. + std::size_t maxlen = std::strlen(info->ai_canonname); + const addrinfo *maxinfo = info; + for (const addrinfo *p = info->ai_next; p != nullptr; p = p->ai_next) { + if (p->ai_canonname == nullptr) { + continue; + } + const std::size_t len = std::strlen(p->ai_canonname); + if (len > maxlen) { + maxlen = len; + maxinfo = p; + } + } + std::string result(maxinfo->ai_canonname); + freeaddrinfo(info); + return result; +#elif defined(_WIN32) + char hostname[256]; + const int r = gethostname(hostname, sizeof(hostname)); + if (r != 0) { + int lasterr = WSAGetLastError(); + throw std::runtime_error( + DEEPHAVEN_LOCATION_STR("gethostname failed: error code ") + + std::to_string(lasterr)); + } + return std::string(hostname); +#else +#error "Unsupported configuration" +#endif +} + +std::optional GetEnv(const std::string& envname) { +#if defined(__unix__) + const char* ret = getenv(envname.c_str()); + if (ret != nullptr) { + return std::string(ret); + } + return {}; +#elif defined(_WIN32) + static char ret[1024]; + size_t len; + const errno_t err = getenv_s(&len, ret, sizeof(ret), envname.c_str()); + if (err == 0) { + return std::string(ret); + } + return {}; +#else +#error "Unsupported configuration" +#endif +} } // namespace deephaven::dhcore::utility diff --git a/cpp-client/deephaven/tests/src/utility_test.cc b/cpp-client/deephaven/tests/src/utility_test.cc index dd600761796..f42dfdc51d8 100644 --- a/cpp-client/deephaven/tests/src/utility_test.cc +++ b/cpp-client/deephaven/tests/src/utility_test.cc @@ -7,7 +7,9 @@ using deephaven::dhcore::utility::Base64Encode; using deephaven::dhcore::utility::Basename; using deephaven::dhcore::utility::EpochMillisToStr; +using deephaven::dhcore::utility::GetEnv; using deephaven::dhcore::utility::GetTidAsString; +using deephaven::dhcore::utility::GetHostname; using deephaven::dhcore::utility::ObjectId; namespace deephaven::client::tests { @@ -45,10 +47,31 @@ TEST_CASE("Basename", "[utility]") { // This isn't much of a test, but if it can compile on all supported // platforms (Linux and Windows) then that is at least a sanity check -// (that the entry point exists). For now we just visuallyi spot-check +// (that the entry point exists). For now we just visually spot-check // that ireturns the right value. TEST_CASE("ThreadId", "[utility]") { auto tid = GetTidAsString(); fmt::println("This should be my thread id: {}", tid); } + +// This isn't much of a test, but if it can compile on all supported +// platforms (Linux and Windows) then that is at least a sanity check +// (that the entry point exists). For now we just visually spot-check +// that ireturns the right value. +TEST_CASE("GetHostname", "[utility]") { + auto hostname = GetHostname(); + fmt::println("This should be the hostname: {}", hostname); +} + +// This isn't much of a test, but if it can compile on all supported +// platforms (Linux and Windows) then that is at least a sanity check +// (that the entry point exists). For now we just visually spot-check +// that ireturns the right value. +TEST_CASE("GetEnv", "[utility]") { + auto path = GetEnv("PATH"); + // Very suspect if neither Windows nor Linux has a PATH set in their + // environment. + REQUIRE(path.has_value()); + fmt::println("PATH is: {}", *path); +} } // namespace deephaven::client::tests