blob: 7a42d4945bc99f04e3a4bf2feb4761fb84144f7a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Utils.hpp"
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <iomanip>
#include <boost/asio.hpp>
#include <boost/dll/import.hpp>
#include <boost/dll/runtime_symbol_info.hpp>
#include <boost/process/detail/config.hpp>
#include "config.h"
#if defined(HAVE_uname)
#include <sys/utsname.h>
#endif
namespace apache {
namespace geode {
namespace client {
std::string Utils::getEnv(const char* varName) {
std::string env;
if (const auto varValue = std::getenv(varName)) {
env = varValue;
}
return env;
}
std::error_code Utils::getLastError() {
if (errno != 0) {
return std::error_code(errno, std::system_category());
}
return boost::process::detail::get_last_error();
}
void Utils::parseEndpointString(const char* endpoints, std::string& host,
uint16_t& port) {
std::string endpointsStr(endpoints);
LOGFINE("Parsing endpoint string [%s]", endpointsStr.c_str());
// Parse this string to get all hostnames and port numbers.
std::string endpoint;
std::string::size_type length = endpointsStr.size();
std::string::size_type pos = 0;
pos = endpointsStr.find(':', 0);
if (pos != std::string::npos) {
endpoint = endpointsStr.substr(0, pos);
pos += 1; // skip ':'
length -= (pos);
endpointsStr = endpointsStr.substr(pos, length);
} else {
host = "";
port = 0;
return;
}
// trim white spaces.
std::string::size_type wpos = endpoint.find_last_not_of(' ');
if (wpos != std::string::npos) {
endpoint.erase(wpos + 1);
wpos = endpoint.find_first_not_of(' ');
if (wpos != std::string::npos) endpoint.erase(0, wpos);
}
host = endpoint;
port = atoi(endpointsStr.c_str());
}
std::string Utils::convertHostToCanonicalForm(const std::string& endpoints) {
using boost::asio::io_service;
using boost::asio::ip::tcp;
if (endpoints.empty()) {
return {};
}
auto pos = endpoints.rfind(':');
if (pos == std::string::npos) {
return {};
}
auto hostname = endpoints.substr(0, pos);
auto port = endpoints.substr(pos + 1);
if (hostname == "localhost") {
hostname = boost::asio::ip::host_name();
}
io_service svc;
boost::system::error_code ec;
tcp::resolver resolver{svc};
auto results = resolver.resolve(hostname, ec);
if (!ec) {
hostname = results->host_name();
}
return hostname + ':' + port;
}
void Utils::parseEndpointNamesString(
std::string endpoints, std::unordered_set<std::string>& endpointNames) {
// Parse this string to get all hostnames and port numbers.
std::string endpoint;
std::string::size_type length = endpoints.size();
std::string::size_type pos = 0;
do {
pos = endpoints.find(',', 0);
if (pos != std::string::npos) {
endpoint = endpoints.substr(0, pos);
pos += 1; // skip ','
length -= (pos);
endpoints = endpoints.substr(pos, length);
} else {
endpoint = endpoints;
}
// trim white spaces.
std::string::size_type wpos = endpoint.find_last_not_of(' ');
if (wpos != std::string::npos) {
endpoint.erase(wpos + 1);
wpos = endpoint.find_first_not_of(' ');
if (wpos != std::string::npos) endpoint.erase(0, wpos);
endpointNames.insert(endpoint);
}
} while (pos != std::string::npos);
}
char* Utils::copyString(const char* str) {
char* resStr = nullptr;
if (str != nullptr) {
size_t strSize = strlen(str) + 1;
resStr = new char[strSize];
memcpy(resStr, str, strSize);
}
return resStr;
}
/**
* Finds, loads and keeps a copy of requested shared library. Future
* improvements should use the boost::dll::import to maintain references to
* shared libraries rather than a synchronized global structure.
*
* Uses similar options ans search patterns to the original ACE_DLL
* implementation.
*
* @param libraryName to find or load
* @return found or loaded shared library
* @throws IllegalArgumentException if library is not found or otherwise
* unloadable.
*/
const boost::dll::shared_library& getSharedLibrary(
const std::string& libraryName) {
static std::mutex sharedLibrariesMutex;
static std::unordered_map<std::string,
std::shared_ptr<boost::dll::shared_library>>
sharedLibraries;
std::lock_guard<decltype(sharedLibrariesMutex)> lock(sharedLibrariesMutex);
const auto& find = sharedLibraries.find(libraryName);
if (find == sharedLibraries.end()) {
auto path = libraryName.empty() ? boost::dll::program_location()
: boost::dll::fs::path{libraryName};
try {
return *sharedLibraries
.emplace(
libraryName,
std::make_shared<boost::dll::shared_library>(
path,
boost::dll::load_mode::rtld_global |
boost::dll::load_mode::rtld_lazy |
boost::dll::load_mode::append_decorations |
boost::dll::load_mode::search_system_folders))
.first->second;
} catch (const boost::dll::fs::system_error& e) {
throw IllegalArgumentException("cannot open library: \"" + path.string() +
"\": reason: " + e.what());
}
}
return *find->second;
}
void* Utils::getFactoryFunctionVoid(const std::string& lib,
const std::string& funcName) {
try {
const auto& sharedLibrary = getSharedLibrary(lib);
return reinterpret_cast<void*>(sharedLibrary.get<void*()>(funcName));
} catch (const boost::dll::fs::system_error&) {
std::string location =
lib.empty() ? "the application" : "library \"" + lib + "\"";
throw IllegalArgumentException("cannot find factory function " + funcName +
" in " + location);
}
}
std::string Utils::convertBytesToString(const uint8_t* bytes, size_t length,
size_t maxLength) {
if (bytes != nullptr) {
length = std::min(length, maxLength);
std::stringstream ss;
ss << std::setfill('0') << std::hex;
for (size_t i = 0; i < length; ++i) {
ss << std::setw(2) << static_cast<int>(bytes[i]);
}
return ss.str();
}
return "";
}
std::string Utils::convertBytesToString(const int8_t* bytes, size_t length,
size_t maxLength) {
return Utils::convertBytesToString(reinterpret_cast<const uint8_t*>(bytes),
length, maxLength);
}
int64_t Utils::startStatOpTime() {
return std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count();
}
void Utils::updateStatOpTime(statistics::Statistics* m_regionStats,
int32_t statId, int64_t start) {
m_regionStats->incLong(statId, startStatOpTime() - start);
}
std::string Utils::getSystemInfo() {
std::string sysname{"Unknown"};
std::string machine{"Unknown"};
std::string nodename{"Unknown"};
std::string release{"Unknown"};
std::string version{"Unknown"};
#if defined(HAVE_uname)
struct utsname name;
auto rc = ::uname(&name);
if (rc == 0) {
sysname = name.sysname;
machine = name.machine;
nodename = name.nodename;
release = name.release;
version = name.version;
}
#elif defined(_WIN32) /* HAVE_uname */
sysname = "Win32";
/* Since MS found it necessary to deprecate these. */
#pragma warning(push)
#pragma warning(disable : 4996)
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif /* __clang__ */
OSVERSIONINFOA vinfo;
vinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
::GetVersionExA(&vinfo);
#if defined(__clang__)
#pragma clang diagnostic pop
#endif /* __clang__ */
#pragma warning(pop)
if (vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
// Get information from the two structures
release = "Windows NT " + std::to_string(vinfo.dwMajorVersion) + '.' +
std::to_string(vinfo.dwMinorVersion);
version = "Build " + std::to_string(vinfo.dwBuildNumber) + ' ' +
vinfo.szCSDVersion;
}
{
HKEY key;
DWORD size = 0;
DWORD type = 0;
auto key_name = "ProcessorNameString";
auto key_path = "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
auto rc = ::RegOpenKeyExA(HKEY_LOCAL_MACHINE, key_path, 0, KEY_READ, &key);
if (rc == ERROR_SUCCESS) {
rc = ::RegQueryValueExA(key, key_name, nullptr, &type, nullptr, &size);
if (rc == ERROR_SUCCESS && type == REG_SZ && size > 0) {
std::vector<char> buffer(size, 0);
auto ptr = reinterpret_cast<LPBYTE>(buffer.data());
rc = ::RegQueryValueExA(key, key_name, nullptr, &type, ptr, &size);
if (rc == ERROR_SUCCESS && buffer[0] != '\0') {
machine = buffer.data();
}
}
::RegCloseKey(key);
}
}
nodename = boost::asio::ip::host_name();
#endif /* _WIN32 */
std::string info = "SystemName=";
info += sysname;
info += " Machine=";
info += machine;
info += " Host=";
info += nodename;
info += " Release=";
info += release;
info += " Version=";
info += version;
return info;
}
} // namespace client
} // namespace geode
} // namespace apache