#include "utils.h"
#include <Slab.h>
#include <glog/logging.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <boost/algorithm/string.hpp>
#include <random>
#ifdef USE_ASCEND_DIRECT
#include "acl/acl.h"
#endif
#include <ylt/coro_http/coro_http_client.hpp>
namespace mooncake {
bool isPortAvailable(int port) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) return false;
int opt = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
bool available = (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0);
close(sock);
return available;
}
AutoPortBinder::AutoPortBinder(int min_port, int max_port)
: socket_fd_(-1), port_(-1) {
static std::random_device rand_gen;
std::mt19937 gen(rand_gen());
std::uniform_int_distribution<> rand_dist(min_port, max_port);
for (int attempt = 0; attempt < 20; ++attempt) {
int port = rand_dist(gen);
socket_fd_ = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd_ < 0) continue;
sockaddr_in addr = {};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if (bind(socket_fd_, (sockaddr *)&addr, sizeof(addr)) == 0) {
port_ = port;
break;
} else {
close(socket_fd_);
socket_fd_ = -1;
}
}
}
AutoPortBinder::~AutoPortBinder() {
if (socket_fd_ >= 0) {
close(socket_fd_);
}
}
void *allocate_buffer_allocator_memory(size_t total_size,
const std::string &protocol,
size_t alignment) {
const size_t default_alignment = facebook::cachelib::Slab::kSize;
if (alignment == default_alignment && total_size < alignment) {
LOG(ERROR) << "Total size must be at least " << alignment;
return nullptr;
}
#ifdef USE_ASCEND_DIRECT
if (protocol == "ascend" && total_size > 0) {
void *buffer = nullptr;
auto ret = aclrtMallocHost(&buffer, total_size);
if (ret != ACL_ERROR_NONE) {
LOG(ERROR) << "Failed to allocate memory: " << ret;
return nullptr;
}
return buffer;
}
#endif
return aligned_alloc(alignment, total_size);
}
void free_memory(const std::string &protocol, void *ptr) {
#ifdef USE_ASCEND_DIRECT
if (protocol == "ascend") {
aclrtFreeHost(ptr);
return;
}
#endif
free(ptr);
}
std::string formatDeviceNames(const std::string &device_names) {
std::stringstream ss(device_names);
std::string item;
std::vector<std::string> tokens;
while (getline(ss, item, ',')) {
tokens.push_back(item);
}
std::string formatted;
for (size_t i = 0; i < tokens.size(); ++i) {
formatted += "\"" + tokens[i] + "\"";
if (i < tokens.size() - 1) {
formatted += ",";
}
}
return formatted;
}
std::vector<std::string> splitString(const std::string &str, char delimiter,
bool trim_spaces, bool keep_empty) {
std::vector<std::string> result;
boost::split(
result, str, boost::is_any_of(std::string(1, delimiter)),
keep_empty ? boost::token_compress_off : boost::token_compress_on);
if (trim_spaces) {
for (auto &token : result) {
boost::trim(token);
}
}
return result;
}
tl::expected<std::string, int> httpGet(const std::string &url) {
coro_http::coro_http_client client;
auto res = client.get(url);
if (res.status == 200) {
return std::string(res.resp_body);
}
return tl::unexpected(res.status);
}
int getFreeTcpPort() {
int sock = ::socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) return -1;
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_port = htons(0);
if (::bind(sock, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)) != 0) {
::close(sock);
return -1;
}
socklen_t len = sizeof(addr);
if (::getsockname(sock, reinterpret_cast<sockaddr *>(&addr), &len) != 0) {
::close(sock);
return -1;
}
int port = ntohs(addr.sin_port);
::close(sock);
return port;
}
}