mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
pow-testgiver support
This commit is contained in:
parent
dbde9c1c40
commit
f064b1047a
257 changed files with 6665 additions and 2608 deletions
|
@ -19,17 +19,55 @@
|
|||
#include "td/utils/port/Clocks.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
|
||||
namespace td {
|
||||
|
||||
ClocksDefault::Duration ClocksDefault::monotonic() {
|
||||
double Clocks::monotonic() {
|
||||
// TODO write system specific functions, because std::chrono::steady_clock is steady only under Windows
|
||||
auto duration = std::chrono::steady_clock::now().time_since_epoch();
|
||||
return static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count()) * 1e-9;
|
||||
}
|
||||
|
||||
ClocksDefault::Duration ClocksDefault::system() {
|
||||
double Clocks::system() {
|
||||
auto duration = std::chrono::system_clock::now().time_since_epoch();
|
||||
return static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count()) * 1e-9;
|
||||
}
|
||||
|
||||
int Clocks::tz_offset() {
|
||||
// not thread-safe on POSIX, so calculate the offset only once
|
||||
static int offset = [] {
|
||||
auto now = std::time(nullptr);
|
||||
|
||||
auto time_ptr = std::localtime(&now);
|
||||
if (time_ptr == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
auto local_time = *time_ptr;
|
||||
|
||||
time_ptr = std::gmtime(&now);
|
||||
if (time_ptr == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
auto utc_time = *time_ptr;
|
||||
|
||||
int minute_offset = local_time.tm_min - utc_time.tm_min;
|
||||
int hour_offset = local_time.tm_hour - utc_time.tm_hour;
|
||||
int day_offset = local_time.tm_mday - utc_time.tm_mday;
|
||||
if (day_offset >= 20) {
|
||||
day_offset = -1;
|
||||
} else if (day_offset <= -20) {
|
||||
day_offset = 1;
|
||||
}
|
||||
int sec_offset = day_offset * 86400 + hour_offset * 3600 + minute_offset * 60;
|
||||
if (sec_offset >= 15 * 3600 || sec_offset <= -15 * 3600) {
|
||||
return 0;
|
||||
}
|
||||
return sec_offset / 900 * 900; // round to 900 just in case
|
||||
}();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int init_tz_offset = Clocks::tz_offset();
|
||||
|
||||
} // namespace td
|
||||
|
|
|
@ -20,21 +20,12 @@
|
|||
|
||||
namespace td {
|
||||
|
||||
class ClocksBase {
|
||||
public:
|
||||
using Duration = double;
|
||||
struct Clocks {
|
||||
static double monotonic();
|
||||
|
||||
static double system();
|
||||
|
||||
static int tz_offset();
|
||||
};
|
||||
|
||||
// TODO: (maybe) write system specific functions.
|
||||
class ClocksDefault {
|
||||
public:
|
||||
using Duration = ClocksBase::Duration;
|
||||
|
||||
static Duration monotonic();
|
||||
|
||||
static Duration system();
|
||||
};
|
||||
|
||||
using Clocks = ClocksDefault;
|
||||
|
||||
} // namespace td
|
||||
|
|
|
@ -18,20 +18,27 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#pragma managed(push, off)
|
||||
#include "td/utils/port/config.h"
|
||||
#pragma managed(pop)
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#undef small
|
||||
|
||||
#if TD_WINRT
|
||||
|
||||
#pragma managed(push, off)
|
||||
#include "td/utils/port/wstring_convert.h"
|
||||
#pragma managed(pop)
|
||||
|
||||
#include "collection.h"
|
||||
|
||||
#pragma managed(push, off)
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#pragma managed(pop)
|
||||
|
||||
#undef small
|
||||
|
||||
#define REF_NEW ref new
|
||||
#define CLRCALL
|
||||
|
@ -102,6 +109,8 @@ inline String^ string_from_unmanaged(const std::string &from) {
|
|||
|
||||
#elif TD_CLI
|
||||
|
||||
#undef small
|
||||
|
||||
#define REF_NEW gcnew
|
||||
#define CLRCALL __clrcall
|
||||
#define DEPRECATED_ATTRIBUTE(message) System::ObsoleteAttribute(message)
|
||||
|
|
|
@ -23,9 +23,11 @@
|
|||
#include "td/utils/port/wstring_convert.h"
|
||||
#endif
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/port/detail/PollableFd.h"
|
||||
#include "td/utils/port/detail/skip_eintr.h"
|
||||
#include "td/utils/port/PollFlags.h"
|
||||
#include "td/utils/port/sleep.h"
|
||||
#include "td/utils/ScopeGuard.h"
|
||||
|
@ -34,8 +36,11 @@
|
|||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
||||
#if TD_PORT_POSIX
|
||||
#include <cerrno>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -43,6 +48,10 @@
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if TD_PORT_WINDOWS && defined(WIN32_LEAN_AND_MEAN)
|
||||
#include <winioctl.h>
|
||||
#endif
|
||||
|
||||
namespace td {
|
||||
|
||||
namespace {
|
||||
|
@ -218,6 +227,12 @@ Result<FileFd> FileFd::open(CSlice filepath, int32 flags, int32 mode) {
|
|||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
return OS_ERROR(PSLICE() << "File \"" << filepath << "\" can't be " << PrintFlags{flags});
|
||||
}
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
||||
if (flags & Write) {
|
||||
DWORD bytes_returned = 0;
|
||||
DeviceIoControl(handle, FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, &bytes_returned, nullptr);
|
||||
}
|
||||
#endif
|
||||
auto native_fd = NativeFd(handle);
|
||||
if (flags & Append) {
|
||||
LARGE_INTEGER offset;
|
||||
|
@ -492,18 +507,58 @@ NativeFd FileFd::move_as_native_fd() {
|
|||
return res;
|
||||
}
|
||||
|
||||
Result<int64> FileFd::get_size() const {
|
||||
TRY_RESULT(s, stat());
|
||||
return s.size_;
|
||||
}
|
||||
|
||||
#if TD_PORT_WINDOWS
|
||||
static uint64 filetime_to_unix_time_nsec(LONGLONG filetime) {
|
||||
namespace {
|
||||
|
||||
uint64 filetime_to_unix_time_nsec(LONGLONG filetime) {
|
||||
const auto FILETIME_UNIX_TIME_DIFF = 116444736000000000ll;
|
||||
return static_cast<uint64>((filetime - FILETIME_UNIX_TIME_DIFF) * 100);
|
||||
}
|
||||
|
||||
struct FileSize {
|
||||
int64 size_;
|
||||
int64 real_size_;
|
||||
};
|
||||
|
||||
Result<FileSize> get_file_size(const FileFd &file_fd) {
|
||||
FILE_STANDARD_INFO standard_info;
|
||||
if (!GetFileInformationByHandleEx(file_fd.get_native_fd().fd(), FileStandardInfo, &standard_info,
|
||||
sizeof(standard_info))) {
|
||||
return OS_ERROR("Get FileStandardInfo failed");
|
||||
}
|
||||
FileSize res;
|
||||
res.size_ = standard_info.EndOfFile.QuadPart;
|
||||
res.real_size_ = standard_info.AllocationSize.QuadPart;
|
||||
|
||||
if (res.size_ > 0 && res.real_size_ <= 0) { // just in case
|
||||
LOG(ERROR) << "Fix real file size from " << res.real_size_ << " to " << res.size_;
|
||||
res.real_size_ = res.size_;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
Result<int64> FileFd::get_size() const {
|
||||
#if TD_PORT_POSIX
|
||||
TRY_RESULT(s, stat());
|
||||
#elif TD_PORT_WINDOWS
|
||||
TRY_RESULT(s, get_file_size(*this));
|
||||
#endif
|
||||
return s.size_;
|
||||
}
|
||||
|
||||
Result<int64> FileFd::get_real_size() const {
|
||||
#if TD_PORT_POSIX
|
||||
TRY_RESULT(s, stat());
|
||||
#elif TD_PORT_WINDOWS
|
||||
TRY_RESULT(s, get_file_size(*this));
|
||||
#endif
|
||||
return s.real_size_;
|
||||
}
|
||||
|
||||
Result<Stat> FileFd::stat() const {
|
||||
CHECK(!empty());
|
||||
#if TD_PORT_POSIX
|
||||
|
@ -521,12 +576,9 @@ Result<Stat> FileFd::stat() const {
|
|||
res.is_dir_ = (basic_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
res.is_reg_ = !res.is_dir_; // TODO this is still wrong
|
||||
|
||||
FILE_STANDARD_INFO standard_info;
|
||||
status = GetFileInformationByHandleEx(get_native_fd().fd(), FileStandardInfo, &standard_info, sizeof(standard_info));
|
||||
if (!status) {
|
||||
return OS_ERROR("Get FileStandardInfo failed");
|
||||
}
|
||||
res.size_ = standard_info.EndOfFile.QuadPart;
|
||||
TRY_RESULT(file_size, get_file_size(*this));
|
||||
res.size_ = file_size.size_;
|
||||
res.real_size_ = file_size.real_size_;
|
||||
|
||||
return res;
|
||||
#endif
|
||||
|
|
|
@ -62,11 +62,15 @@ class FileFd {
|
|||
|
||||
PollableFdInfo &get_poll_info();
|
||||
const PollableFdInfo &get_poll_info() const;
|
||||
|
||||
void close();
|
||||
|
||||
bool empty() const;
|
||||
|
||||
Result<int64> get_size() const;
|
||||
|
||||
Result<int64> get_real_size() const;
|
||||
|
||||
Result<Stat> stat() const;
|
||||
|
||||
Status sync() TD_WARN_UNUSED_RESULT;
|
||||
|
|
|
@ -279,11 +279,11 @@ uint32 IPAddress::get_ipv4() const {
|
|||
return htonl(ipv4_addr_.sin_addr.s_addr);
|
||||
}
|
||||
|
||||
Slice IPAddress::get_ipv6() const {
|
||||
string IPAddress::get_ipv6() const {
|
||||
static_assert(sizeof(ipv6_addr_.sin6_addr) == 16, "ipv6 size == 16");
|
||||
CHECK(is_valid());
|
||||
CHECK(!is_ipv4());
|
||||
return Slice(ipv6_addr_.sin6_addr.s6_addr, 16);
|
||||
return Slice(ipv6_addr_.sin6_addr.s6_addr, 16).str();
|
||||
}
|
||||
|
||||
IPAddress IPAddress::get_any_addr() const {
|
||||
|
@ -320,7 +320,12 @@ void IPAddress::init_ipv6_any() {
|
|||
Status IPAddress::init_ipv6_port(CSlice ipv6, int port) {
|
||||
is_valid_ = false;
|
||||
if (port <= 0 || port >= (1 << 16)) {
|
||||
return Status::Error(PSLICE() << "Invalid [port=" << port << "]");
|
||||
return Status::Error(PSLICE() << "Invalid [IPv6 address port=" << port << "]");
|
||||
}
|
||||
string ipv6_plain;
|
||||
if (ipv6.size() > 2 && ipv6[0] == '[' && ipv6.back() == ']') {
|
||||
ipv6_plain.assign(ipv6.begin() + 1, ipv6.size() - 2);
|
||||
ipv6 = ipv6_plain;
|
||||
}
|
||||
std::memset(&ipv6_addr_, 0, sizeof(ipv6_addr_));
|
||||
ipv6_addr_.sin6_family = AF_INET6;
|
||||
|
@ -342,7 +347,7 @@ Status IPAddress::init_ipv6_as_ipv4_port(CSlice ipv4, int port) {
|
|||
Status IPAddress::init_ipv4_port(CSlice ipv4, int port) {
|
||||
is_valid_ = false;
|
||||
if (port <= 0 || port >= (1 << 16)) {
|
||||
return Status::Error(PSLICE() << "Invalid [port=" << port << "]");
|
||||
return Status::Error(PSLICE() << "Invalid [IPv4 address port=" << port << "]");
|
||||
}
|
||||
std::memset(&ipv4_addr_, 0, sizeof(ipv4_addr_));
|
||||
ipv4_addr_.sin_family = AF_INET;
|
||||
|
@ -357,6 +362,18 @@ Status IPAddress::init_ipv4_port(CSlice ipv4, int port) {
|
|||
return Status::OK();
|
||||
}
|
||||
|
||||
Result<IPAddress> IPAddress::get_ip_address(CSlice host) {
|
||||
auto r_address = get_ipv4_address(host);
|
||||
if (r_address.is_ok()) {
|
||||
return r_address.move_as_ok();
|
||||
}
|
||||
r_address = get_ipv6_address(host);
|
||||
if (r_address.is_ok()) {
|
||||
return r_address.move_as_ok();
|
||||
}
|
||||
return Status::Error("Not a valid IP address");
|
||||
}
|
||||
|
||||
Result<IPAddress> IPAddress::get_ipv4_address(CSlice host) {
|
||||
// sometimes inet_addr allows much more valid IPv4 hosts than inet_pton,
|
||||
// like 0x12.0x34.0x56.0x78, or 0x12345678, or 0x7f.001
|
||||
|
@ -384,6 +401,10 @@ Result<IPAddress> IPAddress::get_ipv6_address(CSlice host) {
|
|||
}
|
||||
|
||||
Status IPAddress::init_host_port(CSlice host, int port, bool prefer_ipv6) {
|
||||
if (host.size() > 2 && host[0] == '[' && host.back() == ']') {
|
||||
return init_ipv6_port(host, port == 0 ? 1 : port);
|
||||
}
|
||||
|
||||
return init_host_port(host, PSLICE() << port, prefer_ipv6);
|
||||
}
|
||||
|
||||
|
@ -398,7 +419,12 @@ Status IPAddress::init_host_port(CSlice host, CSlice port, bool prefer_ipv6) {
|
|||
}
|
||||
#endif
|
||||
TRY_RESULT(ascii_host, idn_to_ascii(host));
|
||||
host = ascii_host;
|
||||
host = ascii_host; // assign string to CSlice
|
||||
|
||||
if (host[0] == '[' && host.back() == ']') {
|
||||
auto port_int = to_integer<int>(port);
|
||||
return init_ipv6_port(host, port_int == 0 ? 1 : port_int);
|
||||
}
|
||||
|
||||
// some getaddrinfo implementations use inet_pton instead of inet_aton and support only decimal-dotted IPv4 form,
|
||||
// and so doesn't recognize 0x12.0x34.0x56.0x78, or 0x12345678, or 0x7f.001 as valid IPv4 addresses
|
||||
|
@ -413,7 +439,7 @@ Status IPAddress::init_host_port(CSlice host, CSlice port, bool prefer_ipv6) {
|
|||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
LOG(DEBUG + 10) << "Try to init IP address of " << host << " with port " << port;
|
||||
LOG(DEBUG + 10) << "Trying to init IP address of " << host << " with port " << port;
|
||||
auto err = getaddrinfo(host.c_str(), port.c_str(), &hints, &info);
|
||||
if (err != 0) {
|
||||
#if TD_WINDOWS
|
||||
|
@ -506,19 +532,19 @@ Status IPAddress::init_peer_address(const SocketFd &socket_fd) {
|
|||
return Status::OK();
|
||||
}
|
||||
|
||||
CSlice IPAddress::ipv4_to_str(uint32 ipv4) {
|
||||
string IPAddress::ipv4_to_str(uint32 ipv4) {
|
||||
ipv4 = ntohl(ipv4);
|
||||
return ::td::get_ip_str(AF_INET, &ipv4);
|
||||
return ::td::get_ip_str(AF_INET, &ipv4).str();
|
||||
}
|
||||
|
||||
CSlice IPAddress::ipv6_to_str(Slice ipv6) {
|
||||
string IPAddress::ipv6_to_str(Slice ipv6) {
|
||||
CHECK(ipv6.size() == 16);
|
||||
return ::td::get_ip_str(AF_INET6, ipv6.ubegin());
|
||||
return ::td::get_ip_str(AF_INET6, ipv6.ubegin()).str();
|
||||
}
|
||||
|
||||
Slice IPAddress::get_ip_str() const {
|
||||
CSlice IPAddress::get_ip_str() const {
|
||||
if (!is_valid()) {
|
||||
return Slice("0.0.0.0");
|
||||
return CSlice("0.0.0.0");
|
||||
}
|
||||
|
||||
switch (get_address_family()) {
|
||||
|
@ -528,7 +554,23 @@ Slice IPAddress::get_ip_str() const {
|
|||
return ::td::get_ip_str(AF_INET, &ipv4_addr_.sin_addr);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return Slice();
|
||||
return CSlice();
|
||||
}
|
||||
}
|
||||
|
||||
string IPAddress::get_ip_host() const {
|
||||
if (!is_valid()) {
|
||||
return "0.0.0.0";
|
||||
}
|
||||
|
||||
switch (get_address_family()) {
|
||||
case AF_INET6:
|
||||
return PSTRING() << '[' << ::td::get_ip_str(AF_INET6, &ipv6_addr_.sin6_addr) << ']';
|
||||
case AF_INET:
|
||||
return ::td::get_ip_str(AF_INET, &ipv4_addr_.sin_addr).str();
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return string();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -611,12 +653,7 @@ StringBuilder &operator<<(StringBuilder &builder, const IPAddress &address) {
|
|||
if (!address.is_valid()) {
|
||||
return builder << "[invalid]";
|
||||
}
|
||||
if (address.get_address_family() == AF_INET) {
|
||||
return builder << "[" << address.get_ip_str() << ":" << address.get_port() << "]";
|
||||
} else {
|
||||
CHECK(address.get_address_family() == AF_INET6);
|
||||
return builder << "[[" << address.get_ip_str() << "]:" << address.get_port() << "]";
|
||||
}
|
||||
return builder << "[" << address.get_ip_host() << ":" << address.get_port() << "]";
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
|
|
@ -51,11 +51,20 @@ class IPAddress {
|
|||
void set_port(int port);
|
||||
|
||||
uint32 get_ipv4() const;
|
||||
Slice get_ipv6() const;
|
||||
Slice get_ip_str() const;
|
||||
string get_ipv6() const;
|
||||
|
||||
// returns result in a static thread-local buffer, which may be overwritten by any subsequent method call
|
||||
CSlice get_ip_str() const;
|
||||
|
||||
// returns IP address as a host, i.e. IPv4 or [IPv6]
|
||||
string get_ip_host() const;
|
||||
|
||||
static string ipv4_to_str(uint32 ipv4);
|
||||
static string ipv6_to_str(Slice ipv6);
|
||||
|
||||
IPAddress get_any_addr() const;
|
||||
|
||||
static Result<IPAddress> get_ip_address(CSlice host); // host must be any IPv4 or IPv6
|
||||
static Result<IPAddress> get_ipv4_address(CSlice host);
|
||||
static Result<IPAddress> get_ipv6_address(CSlice host);
|
||||
|
||||
|
@ -75,8 +84,6 @@ class IPAddress {
|
|||
const sockaddr *get_sockaddr() const;
|
||||
size_t get_sockaddr_len() const;
|
||||
int get_address_family() const;
|
||||
static CSlice ipv4_to_str(uint32 ipv4);
|
||||
static CSlice ipv6_to_str(Slice ipv6);
|
||||
Status init_sockaddr(sockaddr *addr);
|
||||
Status init_sockaddr(sockaddr *addr, socklen_t len) TD_WARN_UNUSED_RESULT;
|
||||
|
||||
|
|
|
@ -22,10 +22,12 @@
|
|||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/port/detail/skip_eintr.h"
|
||||
#include "td/utils/port/IPAddress.h"
|
||||
#include "td/utils/port/PollFlags.h"
|
||||
|
||||
#if TD_PORT_POSIX
|
||||
#include <cerrno>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
|
@ -34,7 +36,6 @@
|
|||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#endif
|
||||
|
||||
#if TD_PORT_WINDOWS
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "td/utils/format.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/port/detail/skip_eintr.h"
|
||||
#include "td/utils/port/PollFlags.h"
|
||||
|
||||
#if TD_PORT_WINDOWS
|
||||
|
@ -32,6 +33,8 @@
|
|||
#endif
|
||||
|
||||
#if TD_PORT_POSIX
|
||||
#include <cerrno>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
|
@ -227,11 +230,11 @@ class SocketFdImpl : private Iocp::Callback {
|
|||
return;
|
||||
}
|
||||
std::memset(&write_overlapped_, 0, sizeof(write_overlapped_));
|
||||
constexpr size_t buf_size = 20;
|
||||
WSABUF buf[buf_size];
|
||||
constexpr size_t BUF_SIZE = 20;
|
||||
WSABUF buf[BUF_SIZE];
|
||||
auto it = output_reader_.clone();
|
||||
size_t buf_i;
|
||||
for (buf_i = 0; buf_i < buf_size; buf_i++) {
|
||||
for (buf_i = 0; buf_i < BUF_SIZE; buf_i++) {
|
||||
auto src = it.prepare_read();
|
||||
if (src.empty()) {
|
||||
break;
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
#include "td/utils/port/Stat.h"
|
||||
|
||||
#include "td/utils/port/detail/PollableFd.h"
|
||||
#include "td/utils/port/FileFd.h"
|
||||
|
||||
#if TD_PORT_POSIX
|
||||
|
@ -27,6 +26,7 @@
|
|||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/port/Clocks.h"
|
||||
#include "td/utils/port/detail/skip_eintr.h"
|
||||
#include "td/utils/ScopeGuard.h"
|
||||
|
||||
#include <utility>
|
||||
|
@ -50,8 +50,20 @@
|
|||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
#elif TD_PORT_WINDOWS
|
||||
|
||||
#include "td/utils/port/thread.h"
|
||||
|
||||
#ifndef PSAPI_VERSION
|
||||
#define PSAPI_VERSION 1
|
||||
#endif
|
||||
#include <psapi.h>
|
||||
|
||||
#endif
|
||||
|
||||
namespace td {
|
||||
|
||||
#if TD_PORT_POSIX
|
||||
namespace detail {
|
||||
|
||||
template <class...>
|
||||
|
@ -118,6 +130,7 @@ Stat from_native_stat(const struct ::stat &buf) {
|
|||
res.atime_nsec_ = static_cast<uint64>(buf.st_atime) * 1000000000 + time_nsec.first;
|
||||
res.mtime_nsec_ = static_cast<uint64>(buf.st_mtime) * 1000000000 + time_nsec.second / 1000 * 1000;
|
||||
res.size_ = buf.st_size;
|
||||
res.real_size_ = buf.st_blocks * 512;
|
||||
res.is_dir_ = (buf.st_mode & S_IFMT) == S_IFDIR;
|
||||
res.is_reg_ = (buf.st_mode & S_IFMT) == S_IFREG;
|
||||
return res;
|
||||
|
@ -187,14 +200,20 @@ Status update_atime(CSlice path) {
|
|||
};
|
||||
return detail::update_atime(file.get_native_fd().fd());
|
||||
}
|
||||
#endif
|
||||
|
||||
Result<Stat> stat(CSlice path) {
|
||||
#if TD_PORT_POSIX
|
||||
struct ::stat buf;
|
||||
int err = detail::skip_eintr([&] { return ::stat(path.c_str(), &buf); });
|
||||
if (err < 0) {
|
||||
return OS_ERROR(PSLICE() << "Stat for file \"" << path << "\" failed");
|
||||
}
|
||||
return detail::from_native_stat(buf);
|
||||
#elif TD_PORT_WINDOWS
|
||||
TRY_RESULT(fd, FileFd::open(path, FileFd::Flags::Read | FileFd::PrivateFlags::WinStat));
|
||||
return fd.stat();
|
||||
#endif
|
||||
}
|
||||
|
||||
Result<MemStat> mem_stat() {
|
||||
|
@ -204,7 +223,7 @@ Result<MemStat> mem_stat() {
|
|||
|
||||
if (KERN_SUCCESS !=
|
||||
task_info(mach_task_self(), TASK_BASIC_INFO, reinterpret_cast<task_info_t>(&t_info), &t_info_count)) {
|
||||
return Status::Error("task_info failed");
|
||||
return Status::Error("Call to task_info failed");
|
||||
}
|
||||
MemStat res;
|
||||
res.resident_size_ = t_info.resident_size;
|
||||
|
@ -262,7 +281,7 @@ Result<MemStat> mem_stat() {
|
|||
LOG(ERROR) << "Failed to parse memory stats " << tag("name", name) << tag("value", value);
|
||||
*x = static_cast<uint64>(-1);
|
||||
} else {
|
||||
*x = r_mem.ok() * 1024; // memory is in kB
|
||||
*x = r_mem.ok() * 1024; // memory is in KB
|
||||
}
|
||||
}
|
||||
if (*s == 0) {
|
||||
|
@ -271,6 +290,19 @@ Result<MemStat> mem_stat() {
|
|||
s++;
|
||||
}
|
||||
|
||||
return res;
|
||||
#elif TD_WINDOWS
|
||||
PROCESS_MEMORY_COUNTERS_EX counters;
|
||||
if (!GetProcessMemoryInfo(GetCurrentProcess(), reinterpret_cast<PROCESS_MEMORY_COUNTERS *>(&counters),
|
||||
sizeof(counters))) {
|
||||
return Status::Error("Call to GetProcessMemoryInfo failed");
|
||||
}
|
||||
|
||||
MemStat res;
|
||||
res.resident_size_ = counters.WorkingSetSize;
|
||||
res.resident_size_peak_ = counters.PeakWorkingSetSize;
|
||||
res.virtual_size_ = counters.PrivateUsage;
|
||||
res.virtual_size_peak_ = counters.PeakPagefileUsage;
|
||||
return res;
|
||||
#else
|
||||
return Status::Error("Not supported");
|
||||
|
@ -287,7 +319,9 @@ Status cpu_stat_self(CpuStat &stat) {
|
|||
constexpr int TMEM_SIZE = 10000;
|
||||
char mem[TMEM_SIZE];
|
||||
TRY_RESULT(size, fd.read(MutableSlice(mem, TMEM_SIZE - 1)));
|
||||
CHECK(size < TMEM_SIZE - 1);
|
||||
if (size >= TMEM_SIZE - 1) {
|
||||
return Status::Error("Failed for read /proc/self/stat");
|
||||
}
|
||||
mem[size] = 0;
|
||||
|
||||
char *s = mem;
|
||||
|
@ -296,10 +330,10 @@ Status cpu_stat_self(CpuStat &stat) {
|
|||
|
||||
while (pass_cnt < 15) {
|
||||
if (pass_cnt == 13) {
|
||||
stat.process_user_ticks = to_integer<uint64>(Slice(s, t));
|
||||
stat.process_user_ticks_ = to_integer<uint64>(Slice(s, t));
|
||||
}
|
||||
if (pass_cnt == 14) {
|
||||
stat.process_system_ticks = to_integer<uint64>(Slice(s, t));
|
||||
stat.process_system_ticks_ = to_integer<uint64>(Slice(s, t));
|
||||
}
|
||||
while (*s && *s != ' ') {
|
||||
s++;
|
||||
|
@ -308,11 +342,12 @@ Status cpu_stat_self(CpuStat &stat) {
|
|||
s++;
|
||||
pass_cnt++;
|
||||
} else {
|
||||
return Status::Error("unexpected end of proc file");
|
||||
return Status::Error("Unexpected end of proc file");
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status cpu_stat_total(CpuStat &stat) {
|
||||
TRY_RESULT(fd, FileFd::open("/proc/stat", FileFd::Read));
|
||||
SCOPE_EXIT {
|
||||
|
@ -322,14 +357,17 @@ Status cpu_stat_total(CpuStat &stat) {
|
|||
constexpr int TMEM_SIZE = 10000;
|
||||
char mem[TMEM_SIZE];
|
||||
TRY_RESULT(size, fd.read(MutableSlice(mem, TMEM_SIZE - 1)));
|
||||
CHECK(size < TMEM_SIZE - 1);
|
||||
if (size >= TMEM_SIZE - 1) {
|
||||
return Status::Error("Failed for read /proc/stat");
|
||||
}
|
||||
mem[size] = 0;
|
||||
|
||||
uint64 sum = 0, cur = 0;
|
||||
uint64 sum = 0;
|
||||
uint64 cur = 0;
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
int c = mem[i];
|
||||
char c = mem[i];
|
||||
if (c >= '0' && c <= '9') {
|
||||
cur = cur * 10 + (uint64)c - '0';
|
||||
cur = cur * 10 + static_cast<uint64>(c) - '0';
|
||||
} else {
|
||||
sum += cur;
|
||||
cur = 0;
|
||||
|
@ -339,7 +377,7 @@ Status cpu_stat_total(CpuStat &stat) {
|
|||
}
|
||||
}
|
||||
|
||||
stat.total_ticks = sum;
|
||||
stat.total_ticks_ = sum;
|
||||
return Status::OK();
|
||||
}
|
||||
#endif
|
||||
|
@ -349,25 +387,28 @@ Result<CpuStat> cpu_stat() {
|
|||
CpuStat stat;
|
||||
TRY_STATUS(cpu_stat_self(stat));
|
||||
TRY_STATUS(cpu_stat_total(stat));
|
||||
return stat;
|
||||
#elif TD_WINDOWS
|
||||
CpuStat stat;
|
||||
stat.total_ticks_ = static_cast<uint64>(GetTickCount64()) * 10000;
|
||||
auto hardware_concurrency = thread::hardware_concurrency();
|
||||
if (hardware_concurrency != 0) {
|
||||
stat.total_ticks_ *= hardware_concurrency;
|
||||
}
|
||||
|
||||
FILETIME ignored_time;
|
||||
FILETIME kernel_time;
|
||||
FILETIME user_time;
|
||||
if (!GetProcessTimes(GetCurrentProcess(), &ignored_time, &ignored_time, &kernel_time, &user_time)) {
|
||||
return Status::Error("Failed to call GetProcessTimes");
|
||||
}
|
||||
stat.process_system_ticks_ = kernel_time.dwLowDateTime + (static_cast<uint64>(kernel_time.dwHighDateTime) << 32);
|
||||
stat.process_user_ticks_ = user_time.dwLowDateTime + (static_cast<uint64>(user_time.dwHighDateTime) << 32);
|
||||
|
||||
return stat;
|
||||
#else
|
||||
return Status::Error("Not supported");
|
||||
#endif
|
||||
}
|
||||
} // namespace td
|
||||
#endif
|
||||
|
||||
#if TD_PORT_WINDOWS
|
||||
namespace td {
|
||||
|
||||
Result<Stat> stat(CSlice path) {
|
||||
TRY_RESULT(fd, FileFd::open(path, FileFd::Flags::Read | FileFd::PrivateFlags::WinStat));
|
||||
return fd.stat();
|
||||
}
|
||||
|
||||
Result<CpuStat> cpu_stat() {
|
||||
return Status::Error("Not supported");
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
#endif
|
||||
|
|
|
@ -30,6 +30,7 @@ struct Stat {
|
|||
bool is_dir_;
|
||||
bool is_reg_;
|
||||
int64 size_;
|
||||
int64 real_size_;
|
||||
uint64 atime_nsec_;
|
||||
uint64 mtime_nsec_;
|
||||
};
|
||||
|
@ -37,20 +38,13 @@ struct Stat {
|
|||
Result<Stat> stat(CSlice path) TD_WARN_UNUSED_RESULT;
|
||||
|
||||
struct CpuStat {
|
||||
uint64 total_ticks{0};
|
||||
uint64 process_user_ticks{0};
|
||||
uint64 process_system_ticks{0};
|
||||
uint64 total_ticks_{0};
|
||||
uint64 process_user_ticks_{0};
|
||||
uint64 process_system_ticks_{0};
|
||||
};
|
||||
|
||||
Result<CpuStat> cpu_stat() TD_WARN_UNUSED_RESULT;
|
||||
|
||||
#if TD_PORT_POSIX
|
||||
|
||||
namespace detail {
|
||||
Result<Stat> fstat(int native_fd);
|
||||
} // namespace detail
|
||||
|
||||
Status update_atime(CSlice path) TD_WARN_UNUSED_RESULT;
|
||||
|
||||
struct MemStat {
|
||||
uint64 resident_size_ = 0;
|
||||
uint64 resident_size_peak_ = 0;
|
||||
|
@ -60,6 +54,14 @@ struct MemStat {
|
|||
|
||||
Result<MemStat> mem_stat() TD_WARN_UNUSED_RESULT;
|
||||
|
||||
#if TD_PORT_POSIX
|
||||
|
||||
namespace detail {
|
||||
Result<Stat> fstat(int native_fd);
|
||||
} // namespace detail
|
||||
|
||||
Status update_atime(CSlice path) TD_WARN_UNUSED_RESULT;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace td
|
||||
|
|
|
@ -35,8 +35,7 @@ namespace td {
|
|||
template <int id>
|
||||
static FileFd &get_file_fd() {
|
||||
static FileFd result = FileFd::from_native_fd(NativeFd(id, true));
|
||||
static auto guard = td::ScopeExit() + [&] { result.move_as_native_fd().release(); };
|
||||
assert(!result.empty());
|
||||
static auto guard = ScopeExit() + [&] { result.move_as_native_fd().release(); };
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -56,7 +55,7 @@ static FileFd &get_file_fd() {
|
|||
static auto handle = GetStdHandle(id);
|
||||
LOG_IF(FATAL, handle == INVALID_HANDLE_VALUE) << "Failed to GetStdHandle " << id;
|
||||
static FileFd result = FileFd::from_native_fd(NativeFd(handle, true));
|
||||
static auto guard = td::ScopeExit() + [&] { result.move_as_native_fd().release(); };
|
||||
static auto guard = ScopeExit() + [&] { result.move_as_native_fd().release(); };
|
||||
#else
|
||||
static FileFd result;
|
||||
#endif
|
||||
|
@ -81,7 +80,7 @@ class BufferedStdinImpl : public Iocp::Callback {
|
|||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
||||
BufferedStdinImpl() : info_(NativeFd(GetStdHandle(STD_INPUT_HANDLE), true)) {
|
||||
iocp_ref_ = Iocp::get()->get_ref();
|
||||
read_thread_ = td::thread([this] { this->read_loop(); });
|
||||
read_thread_ = thread([this] { this->read_loop(); });
|
||||
}
|
||||
#else
|
||||
BufferedStdinImpl() {
|
||||
|
@ -121,7 +120,7 @@ class BufferedStdinImpl : public Iocp::Callback {
|
|||
PollableFdInfo info_;
|
||||
ChainBufferWriter writer_;
|
||||
ChainBufferReader reader_ = writer_.extract_reader();
|
||||
td::thread read_thread_;
|
||||
thread read_thread_;
|
||||
std::atomic<bool> close_flag_{false};
|
||||
IocpRef iocp_ref_;
|
||||
std::atomic<int> refcnt_{1};
|
||||
|
@ -144,7 +143,7 @@ class BufferedStdinImpl : public Iocp::Callback {
|
|||
}
|
||||
}
|
||||
void on_iocp(Result<size_t> r_size, WSAOVERLAPPED *overlapped) override {
|
||||
info_.add_flags_from_poll(td::PollFlags::Read());
|
||||
info_.add_flags_from_poll(PollFlags::Read());
|
||||
dec_refcnt();
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "td/utils/format.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/port/detail/skip_eintr.h"
|
||||
#include "td/utils/port/PollFlags.h"
|
||||
#include "td/utils/port/SocketFd.h"
|
||||
#include "td/utils/VectorQueue.h"
|
||||
|
@ -32,6 +33,8 @@
|
|||
#endif
|
||||
|
||||
#if TD_PORT_POSIX
|
||||
#include <cerrno>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
|
@ -73,7 +76,7 @@ class UdpSocketReceiveHelper {
|
|||
message.error = Status::OK();
|
||||
|
||||
if ((message_header.dwFlags & (MSG_TRUNC | MSG_CTRUNC)) != 0) {
|
||||
message.error = Status::Error(501, "message too long");
|
||||
message.error = Status::Error(501, "Message too long");
|
||||
message.data = BufferSlice();
|
||||
return;
|
||||
}
|
||||
|
@ -179,7 +182,8 @@ class UdpSocketFdImpl : private Iocp::Callback {
|
|||
UdpMessage to_receive_;
|
||||
WSAMSG receive_message_;
|
||||
UdpSocketReceiveHelper receive_helper_;
|
||||
enum : size_t { MAX_PACKET_SIZE = 2048, RESERVED_SIZE = MAX_PACKET_SIZE * 8 };
|
||||
static constexpr size_t MAX_PACKET_SIZE = 2048;
|
||||
static constexpr size_t RESERVED_SIZE = MAX_PACKET_SIZE * 8;
|
||||
BufferSlice receive_buffer_;
|
||||
|
||||
UdpMessage to_send_;
|
||||
|
@ -434,7 +438,7 @@ class UdpSocketReceiveHelper {
|
|||
}
|
||||
if (message_header.msg_flags & MSG_TRUNC) {
|
||||
if (message.error) {
|
||||
*message.error = Status::Error(501, "message too long");
|
||||
*message.error = Status::Error(501, "Message too long");
|
||||
}
|
||||
message.data.truncate(0);
|
||||
return;
|
||||
|
@ -822,11 +826,11 @@ static Result<uint32> maximize_buffer(int socket_fd, int optname, uint32 max) {
|
|||
}
|
||||
|
||||
Result<uint32> UdpSocketFd::maximize_snd_buffer(uint32 max) {
|
||||
return maximize_buffer(get_native_fd().fd(), SO_SNDBUF, max == 0 ? default_udp_max_snd_buffer_size : max);
|
||||
return maximize_buffer(get_native_fd().fd(), SO_SNDBUF, max == 0 ? DEFAULT_UDP_MAX_SND_BUFFER_SIZE : max);
|
||||
}
|
||||
|
||||
Result<uint32> UdpSocketFd::maximize_rcv_buffer(uint32 max) {
|
||||
return maximize_buffer(get_native_fd().fd(), SO_RCVBUF, max == 0 ? default_udp_max_rcv_buffer_size : max);
|
||||
return maximize_buffer(get_native_fd().fd(), SO_RCVBUF, max == 0 ? DEFAULT_UDP_MAX_RCV_BUFFER_SIZE : max);
|
||||
}
|
||||
#else
|
||||
Result<uint32> UdpSocketFd::maximize_snd_buffer(uint32 max) {
|
||||
|
|
|
@ -96,8 +96,8 @@ class UdpSocketFd {
|
|||
#endif
|
||||
|
||||
private:
|
||||
static constexpr uint32 default_udp_max_snd_buffer_size = (1 << 24);
|
||||
static constexpr uint32 default_udp_max_rcv_buffer_size = (1 << 24);
|
||||
static constexpr uint32 DEFAULT_UDP_MAX_SND_BUFFER_SIZE = (1 << 24);
|
||||
static constexpr uint32 DEFAULT_UDP_MAX_RCV_BUFFER_SIZE = (1 << 24);
|
||||
std::unique_ptr<detail::UdpSocketFdImpl, detail::UdpSocketFdImplDeleter> impl_;
|
||||
explicit UdpSocketFd(unique_ptr<detail::UdpSocketFdImpl> impl);
|
||||
};
|
||||
|
|
|
@ -26,6 +26,8 @@ char disable_linker_warning_about_empty_file_epoll_cpp TD_UNUSED;
|
|||
#include "td/utils/logging.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace td {
|
||||
|
@ -82,7 +84,8 @@ void Epoll::unsubscribe(PollableFdRef fd_ref) {
|
|||
int err = epoll_ctl(epoll_fd_.fd(), EPOLL_CTL_DEL, native_fd, nullptr);
|
||||
auto epoll_ctl_errno = errno;
|
||||
LOG_IF(FATAL, err == -1) << Status::PosixError(epoll_ctl_errno, "epoll_ctl DEL failed")
|
||||
<< ", epoll_fd = " << epoll_fd_.fd() << ", fd = " << native_fd << fd.native_fd().validate();
|
||||
<< ", epoll_fd = " << epoll_fd_.fd() << ", fd = " << native_fd
|
||||
<< ", status = " << fd.native_fd().validate();
|
||||
}
|
||||
|
||||
void Epoll::unsubscribe_before_close(PollableFdRef fd) {
|
||||
|
|
|
@ -28,6 +28,8 @@ char disable_linker_warning_about_empty_file_event_fd_bsd_cpp TD_UNUSED;
|
|||
#include "td/utils/port/SocketFd.h"
|
||||
#include "td/utils/Slice.h"
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <sys/socket.h>
|
||||
|
|
|
@ -25,10 +25,13 @@ char disable_linker_warning_about_empty_file_event_fd_linux_cpp TD_UNUSED;
|
|||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/port/detail/NativeFd.h"
|
||||
#include "td/utils/port/detail/skip_eintr.h"
|
||||
#include "td/utils/port/PollFlags.h"
|
||||
#include "td/utils/ScopeGuard.h"
|
||||
#include "td/utils/Slice.h"
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
#include <poll.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <unistd.h>
|
||||
|
|
|
@ -25,6 +25,7 @@ char disable_linker_warning_about_empty_file_kqueue_cpp TD_UNUSED;
|
|||
#include "td/utils/logging.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <utility>
|
||||
|
||||
#include <sys/time.h>
|
||||
|
|
|
@ -38,7 +38,9 @@ namespace td {
|
|||
class FdSet {
|
||||
public:
|
||||
void on_create_fd(NativeFd::Fd fd) {
|
||||
CHECK(is_valid(fd));
|
||||
if (!is_valid(fd)) {
|
||||
return;
|
||||
}
|
||||
if (is_stdio(fd)) {
|
||||
return;
|
||||
}
|
||||
|
@ -64,7 +66,9 @@ class FdSet {
|
|||
}
|
||||
|
||||
void on_close_fd(NativeFd::Fd fd) {
|
||||
CHECK(is_valid(fd));
|
||||
if (!is_valid(fd)) {
|
||||
return;
|
||||
}
|
||||
if (is_stdio(fd)) {
|
||||
return;
|
||||
}
|
||||
|
@ -112,7 +116,7 @@ FdSet &get_fd_set() {
|
|||
|
||||
Status NativeFd::validate() const {
|
||||
#if TD_FD_DEBUG
|
||||
return get_fd_set().validate(fd_.get());
|
||||
return get_fd_set().validate(fd_);
|
||||
#else
|
||||
return Status::OK();
|
||||
#endif
|
||||
|
@ -121,13 +125,13 @@ Status NativeFd::validate() const {
|
|||
NativeFd::NativeFd(Fd fd) : fd_(fd) {
|
||||
VLOG(fd) << *this << " create";
|
||||
#if TD_FD_DEBUG
|
||||
get_fd_set().on_create_fd(fd_.get());
|
||||
get_fd_set().on_create_fd(fd_);
|
||||
#endif
|
||||
}
|
||||
|
||||
NativeFd::NativeFd(Fd fd, bool nolog) : fd_(fd) {
|
||||
#if TD_FD_DEBUG
|
||||
get_fd_set().on_create_fd(fd_.get());
|
||||
get_fd_set().on_create_fd(fd_);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -135,18 +139,26 @@ NativeFd::NativeFd(Fd fd, bool nolog) : fd_(fd) {
|
|||
NativeFd::NativeFd(Socket socket) : fd_(reinterpret_cast<Fd>(socket)), is_socket_(true) {
|
||||
VLOG(fd) << *this << " create";
|
||||
#if TD_FD_DEBUG
|
||||
get_fd_set().on_create_fd(fd_.get());
|
||||
get_fd_set().on_create_fd(fd_);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
NativeFd &NativeFd::operator=(NativeFd &&from) {
|
||||
CHECK(this != &from);
|
||||
close();
|
||||
fd_ = std::move(from.fd_);
|
||||
NativeFd::NativeFd(NativeFd &&other) : fd_(other.fd_) {
|
||||
#if TD_PORT_WINDOWS
|
||||
is_socket_ = from.is_socket_;
|
||||
is_socket_ = other.is_socket_;
|
||||
#endif
|
||||
other.fd_ = empty_fd();
|
||||
}
|
||||
|
||||
NativeFd &NativeFd::operator=(NativeFd &&other) {
|
||||
CHECK(this != &other);
|
||||
close();
|
||||
fd_ = other.fd_;
|
||||
#if TD_PORT_WINDOWS
|
||||
is_socket_ = other.is_socket_;
|
||||
#endif
|
||||
other.fd_ = empty_fd();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -155,7 +167,7 @@ NativeFd::~NativeFd() {
|
|||
}
|
||||
|
||||
NativeFd::operator bool() const {
|
||||
return fd_.get() != empty_fd();
|
||||
return fd_ != empty_fd();
|
||||
}
|
||||
|
||||
NativeFd::Fd NativeFd::empty_fd() {
|
||||
|
@ -167,7 +179,7 @@ NativeFd::Fd NativeFd::empty_fd() {
|
|||
}
|
||||
|
||||
NativeFd::Fd NativeFd::fd() const {
|
||||
return fd_.get();
|
||||
return fd_;
|
||||
}
|
||||
|
||||
NativeFd::Socket NativeFd::socket() const {
|
||||
|
@ -175,7 +187,7 @@ NativeFd::Socket NativeFd::socket() const {
|
|||
return fd();
|
||||
#elif TD_PORT_WINDOWS
|
||||
CHECK(is_socket_);
|
||||
return reinterpret_cast<Socket>(fd_.get());
|
||||
return reinterpret_cast<Socket>(fd_);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -239,13 +251,13 @@ void NativeFd::close() {
|
|||
auto error = OS_ERROR("Close fd");
|
||||
LOG(ERROR) << error;
|
||||
}
|
||||
fd_ = {};
|
||||
fd_ = empty_fd();
|
||||
}
|
||||
|
||||
NativeFd::Fd NativeFd::release() {
|
||||
VLOG(fd) << *this << " release";
|
||||
auto res = fd_.get();
|
||||
fd_ = {};
|
||||
auto res = fd_;
|
||||
fd_ = empty_fd();
|
||||
#if TD_FD_DEBUG
|
||||
get_fd_set().on_close_fd(res);
|
||||
#endif
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "td/utils/port/config.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/MovableValue.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
|
@ -37,8 +36,6 @@ class NativeFd {
|
|||
using Socket = SOCKET;
|
||||
#endif
|
||||
NativeFd() = default;
|
||||
NativeFd(NativeFd &&) = default;
|
||||
NativeFd &operator=(NativeFd &&);
|
||||
explicit NativeFd(Fd fd);
|
||||
NativeFd(Fd fd, bool nolog);
|
||||
#if TD_PORT_WINDOWS
|
||||
|
@ -46,12 +43,12 @@ class NativeFd {
|
|||
#endif
|
||||
NativeFd(const NativeFd &) = delete;
|
||||
NativeFd &operator=(const NativeFd &) = delete;
|
||||
NativeFd(NativeFd &&other);
|
||||
NativeFd &operator=(NativeFd &&other);
|
||||
~NativeFd();
|
||||
|
||||
explicit operator bool() const;
|
||||
|
||||
static Fd empty_fd();
|
||||
|
||||
Fd fd() const;
|
||||
Socket socket() const;
|
||||
|
||||
|
@ -67,10 +64,10 @@ class NativeFd {
|
|||
Status validate() const;
|
||||
|
||||
private:
|
||||
#if TD_PORT_POSIX
|
||||
MovableValue<Fd, -1> fd_;
|
||||
#elif TD_PORT_WINDOWS
|
||||
MovableValue<Fd, INVALID_HANDLE_VALUE> fd_;
|
||||
static Fd empty_fd();
|
||||
|
||||
Fd fd_ = empty_fd();
|
||||
#if TD_PORT_WINDOWS
|
||||
bool is_socket_{false};
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -28,6 +28,8 @@ char disable_linker_warning_about_empty_file_poll_cpp TD_UNUSED;
|
|||
#include "td/utils/ScopeGuard.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
namespace td {
|
||||
namespace detail {
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
|
||||
|
@ -220,30 +219,6 @@ inline const NativeFd &PollableFd::native_fd() const {
|
|||
return fd_info_->native_fd();
|
||||
}
|
||||
|
||||
#if TD_PORT_POSIX
|
||||
namespace detail {
|
||||
template <class F>
|
||||
auto skip_eintr(F &&f) {
|
||||
decltype(f()) res;
|
||||
static_assert(std::is_integral<decltype(res)>::value, "integral type expected");
|
||||
do {
|
||||
errno = 0; // just in case
|
||||
res = f();
|
||||
} while (res < 0 && errno == EINTR);
|
||||
return res;
|
||||
}
|
||||
template <class F>
|
||||
auto skip_eintr_cstr(F &&f) {
|
||||
char *res;
|
||||
do {
|
||||
errno = 0; // just in case
|
||||
res = f();
|
||||
} while (res == nullptr && errno == EINTR);
|
||||
return res;
|
||||
}
|
||||
} // namespace detail
|
||||
#endif
|
||||
|
||||
template <class FdT>
|
||||
bool can_read(const FdT &fd) {
|
||||
return fd.get_poll_info().get_flags().can_read() || fd.get_poll_info().get_flags().has_pending_error();
|
||||
|
|
114
tdutils/td/utils/port/detail/ThreadPthread.cpp
Normal file
114
tdutils/td/utils/port/detail/ThreadPthread.cpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
|
||||
#include "td/utils/port/detail/ThreadPthread.h"
|
||||
|
||||
char disable_linker_warning_about_empty_file_thread_pthread_cpp TD_UNUSED;
|
||||
|
||||
#if TD_THREAD_PTHREAD
|
||||
|
||||
#include "td/utils/misc.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#if TD_FREEBSD || TD_OPENBSD || TD_NETBSD
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
|
||||
namespace td {
|
||||
namespace detail {
|
||||
unsigned ThreadPthread::hardware_concurrency() {
|
||||
// Linux and macOS
|
||||
#if defined(_SC_NPROCESSORS_ONLN)
|
||||
{
|
||||
auto res = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
if (res > 0) {
|
||||
return narrow_cast<unsigned>(res);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TD_FREEBSD || TD_OPENBSD || TD_NETBSD
|
||||
#if defined(HW_AVAILCPU) && defined(CTL_HW)
|
||||
{
|
||||
int mib[2] = {CTL_HW, HW_AVAILCPU};
|
||||
int res{0};
|
||||
size_t len = sizeof(res);
|
||||
if (sysctl(mib, 2, &res, &len, nullptr, 0) == 0 && res != 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HW_NCPU) && defined(CTL_HW)
|
||||
{
|
||||
int mib[2] = {CTL_HW, HW_NCPU};
|
||||
int res{0};
|
||||
size_t len = sizeof(res);
|
||||
if (sysctl(mib, 2, &res, &len, nullptr, 0) == 0 && res != 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Just in case
|
||||
return 8;
|
||||
}
|
||||
|
||||
void ThreadPthread::set_name(CSlice name) {
|
||||
#if defined(_GNU_SOURCE) && defined(__GLIBC_PREREQ)
|
||||
#if __GLIBC_PREREQ(2, 12)
|
||||
pthread_setname_np(thread_, name.c_str());
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void ThreadPthread::join() {
|
||||
if (is_inited_.get()) {
|
||||
is_inited_ = false;
|
||||
pthread_join(thread_, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPthread::detach() {
|
||||
if (is_inited_.get()) {
|
||||
is_inited_ = false;
|
||||
pthread_detach(thread_);
|
||||
}
|
||||
}
|
||||
|
||||
int ThreadPthread::do_pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *),
|
||||
void *arg) {
|
||||
return pthread_create(thread, attr, start_routine, arg);
|
||||
}
|
||||
|
||||
namespace this_thread_pthread {
|
||||
void yield() {
|
||||
sched_yield();
|
||||
}
|
||||
ThreadPthread::id get_id() {
|
||||
return pthread_self();
|
||||
}
|
||||
} // namespace this_thread_pthread
|
||||
|
||||
} // namespace detail
|
||||
} // namespace td
|
||||
#endif
|
|
@ -34,8 +34,7 @@
|
|||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace td {
|
||||
namespace detail {
|
||||
|
@ -44,7 +43,8 @@ class ThreadPthread {
|
|||
ThreadPthread() = default;
|
||||
ThreadPthread(const ThreadPthread &other) = delete;
|
||||
ThreadPthread &operator=(const ThreadPthread &other) = delete;
|
||||
ThreadPthread(ThreadPthread &&) = default;
|
||||
ThreadPthread(ThreadPthread &&other) noexcept : is_inited_(std::move(other.is_inited_)), thread_(other.thread_) {
|
||||
}
|
||||
ThreadPthread &operator=(ThreadPthread &&other) {
|
||||
join();
|
||||
is_inited_ = std::move(other.is_inited_);
|
||||
|
@ -58,36 +58,20 @@ class ThreadPthread {
|
|||
invoke_tuple(std::move(args));
|
||||
clear_thread_locals();
|
||||
});
|
||||
pthread_create(&thread_, nullptr, run_thread, func.release());
|
||||
do_pthread_create(&thread_, nullptr, run_thread, func.release());
|
||||
is_inited_ = true;
|
||||
}
|
||||
void set_name(CSlice name) {
|
||||
#if defined(_GNU_SOURCE) && defined(__GLIBC_PREREQ)
|
||||
#if __GLIBC_PREREQ(2, 12)
|
||||
pthread_setname_np(thread_, name.c_str());
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
void join() {
|
||||
if (is_inited_.get()) {
|
||||
is_inited_ = false;
|
||||
pthread_join(thread_, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void detach() {
|
||||
if (is_inited_.get()) {
|
||||
is_inited_ = false;
|
||||
pthread_detach(thread_);
|
||||
}
|
||||
}
|
||||
~ThreadPthread() {
|
||||
join();
|
||||
}
|
||||
|
||||
static unsigned hardware_concurrency() {
|
||||
return 8;
|
||||
}
|
||||
void set_name(CSlice name);
|
||||
|
||||
void join();
|
||||
|
||||
void detach();
|
||||
|
||||
static unsigned hardware_concurrency();
|
||||
|
||||
using id = pthread_t;
|
||||
|
||||
|
@ -100,6 +84,8 @@ class ThreadPthread {
|
|||
return std::forward<T>(v);
|
||||
}
|
||||
|
||||
int do_pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
|
||||
|
||||
static void *run_thread(void *ptr) {
|
||||
ThreadIdGuard thread_id_guard;
|
||||
auto func = unique_ptr<Destructor>(static_cast<Destructor *>(ptr));
|
||||
|
@ -108,12 +94,8 @@ class ThreadPthread {
|
|||
};
|
||||
|
||||
namespace this_thread_pthread {
|
||||
inline void yield() {
|
||||
sched_yield();
|
||||
}
|
||||
inline ThreadPthread::id get_id() {
|
||||
return pthread_self();
|
||||
}
|
||||
void yield();
|
||||
ThreadPthread::id get_id();
|
||||
} // namespace this_thread_pthread
|
||||
} // namespace detail
|
||||
} // namespace td
|
||||
|
|
52
tdutils/td/utils/port/detail/skip_eintr.h
Normal file
52
tdutils/td/utils/port/detail/skip_eintr.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cerrno>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
|
||||
#if TD_PORT_POSIX
|
||||
namespace detail {
|
||||
template <class F>
|
||||
auto skip_eintr(F &&f) {
|
||||
decltype(f()) res;
|
||||
static_assert(std::is_integral<decltype(res)>::value, "integral type expected");
|
||||
do {
|
||||
errno = 0; // just in case
|
||||
res = f();
|
||||
} while (res < 0 && errno == EINTR);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class F>
|
||||
auto skip_eintr_cstr(F &&f) {
|
||||
char *res;
|
||||
do {
|
||||
errno = 0; // just in case
|
||||
res = f();
|
||||
} while (res == nullptr && errno == EINTR);
|
||||
return res;
|
||||
}
|
||||
} // namespace detail
|
||||
#endif
|
||||
|
||||
} // namespace td
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/port/detail/PollableFd.h"
|
||||
#include "td/utils/port/detail/skip_eintr.h"
|
||||
#include "td/utils/ScopeGuard.h"
|
||||
|
||||
#if TD_PORT_WINDOWS
|
||||
|
@ -55,6 +55,7 @@
|
|||
#include <sys/syslimits.h>
|
||||
#endif
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
|
@ -68,8 +69,7 @@ Status set_temporary_dir(CSlice dir) {
|
|||
input_dir += TD_DIR_SLASH;
|
||||
}
|
||||
TRY_STATUS(mkpath(input_dir, 0750));
|
||||
TRY_RESULT(real_dir, realpath(input_dir));
|
||||
temporary_dir = std::move(real_dir);
|
||||
TRY_RESULT_ASSIGN(temporary_dir, realpath(input_dir));
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
|
@ -431,8 +431,7 @@ Result<string> realpath(CSlice slice, bool ignore_access_denied) {
|
|||
return OS_ERROR(PSLICE() << "GetFullPathNameW failed for \"" << slice << '"');
|
||||
}
|
||||
} else {
|
||||
TRY_RESULT(t_res, from_wstring(buf));
|
||||
res = std::move(t_res);
|
||||
TRY_RESULT_ASSIGN(res, from_wstring(buf));
|
||||
}
|
||||
if (res.empty()) {
|
||||
return Status::Error("Empty path");
|
||||
|
|
|
@ -14,14 +14,19 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2019-2020 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "rlimit.h"
|
||||
#if TD_LINUX || TD_ANDROID
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "td/utils/port/rlimit.h"
|
||||
|
||||
#include "td/utils/port/config.h"
|
||||
|
||||
#include "td/utils/misc.h"
|
||||
|
||||
#if TD_PORT_POSIX
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
namespace td {
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/port/config.h"
|
||||
#include "td/utils/port/platform.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
namespace td {
|
||||
|
@ -28,5 +28,4 @@ enum class RlimitType { nofile, rss };
|
|||
|
||||
td::Status change_rlimit(RlimitType rlim_type, td::uint64 value, td::uint64 cap = 0);
|
||||
td::Status change_maximize_rlimit(RlimitType rlim, td::uint64 value);
|
||||
|
||||
} // namespace td
|
||||
|
|
|
@ -301,7 +301,7 @@ void signal_safe_write_pointer(void *p, bool add_header) {
|
|||
char *ptr = end;
|
||||
*--ptr = '\n';
|
||||
do {
|
||||
*--ptr = td::format::hex_digit(addr % 16);
|
||||
*--ptr = format::hex_digit(addr % 16);
|
||||
addr /= 16;
|
||||
} while (addr != 0);
|
||||
*--ptr = 'x';
|
||||
|
@ -318,6 +318,7 @@ static void block_stdin() {
|
|||
}
|
||||
|
||||
static void default_failure_signal_handler(int sig) {
|
||||
Stacktrace::init();
|
||||
signal_safe_write_signal_number(sig);
|
||||
|
||||
Stacktrace::PrintOptions options;
|
||||
|
|
|
@ -65,10 +65,12 @@ void print_backtrace_gdb(void) {
|
|||
name_buf[res] = 0;
|
||||
|
||||
#if TD_LINUX
|
||||
#if defined(PR_SET_DUMPABLE)
|
||||
if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
|
||||
signal_safe_write("Can't set dumpable\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if defined(PR_SET_PTRACER)
|
||||
// We can't use event fd because we are in a signal handler
|
||||
int fds[2];
|
||||
|
@ -120,10 +122,18 @@ void print_backtrace_gdb(void) {
|
|||
} // namespace
|
||||
|
||||
void Stacktrace::print_to_stderr(const PrintOptions &options) {
|
||||
print_backtrace();
|
||||
if (options.use_gdb) {
|
||||
print_backtrace_gdb();
|
||||
}
|
||||
print_backtrace();
|
||||
}
|
||||
|
||||
void Stacktrace::init() {
|
||||
#if __GLIBC__
|
||||
// backtrace needs to be called once to ensure that next calls are async-signal-safe
|
||||
void *buffer[1];
|
||||
backtrace(buffer, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
|
|
@ -28,6 +28,8 @@ class Stacktrace {
|
|||
}
|
||||
};
|
||||
static void print_to_stderr(const PrintOptions &options = PrintOptions());
|
||||
|
||||
static void init();
|
||||
};
|
||||
|
||||
} // namespace td
|
||||
|
|
172
tdutils/td/utils/port/uname.cpp
Normal file
172
tdutils/td/utils/port/uname.cpp
Normal file
|
@ -0,0 +1,172 @@
|
|||
#include "td/utils/port/uname.h"
|
||||
|
||||
#include "td/utils/port/config.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/port/Stat.h"
|
||||
|
||||
#if TD_PORT_POSIX
|
||||
|
||||
#if TD_ANDROID
|
||||
#include <sys/system_properties.h>
|
||||
#else
|
||||
#if TD_DARWIN
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
namespace td {
|
||||
|
||||
#if TD_DARWIN || TD_LINUX
|
||||
static string read_os_name(CSlice os_version_file_path, CSlice prefix, CSlice suffix) {
|
||||
auto r_stat = stat(os_version_file_path);
|
||||
if (r_stat.is_ok() && r_stat.ok().is_reg_ && r_stat.ok().size_ < (1 << 16)) {
|
||||
auto r_file = read_file_str(os_version_file_path, r_stat.ok().size_);
|
||||
if (r_file.is_ok()) {
|
||||
auto begin_pos = r_file.ok().find(prefix.c_str());
|
||||
if (begin_pos != string::npos) {
|
||||
begin_pos += prefix.size();
|
||||
auto end_pos = r_file.ok().find(suffix.c_str(), begin_pos);
|
||||
if (end_pos != string::npos) {
|
||||
auto os_version = trim(r_file.ok().substr(begin_pos, end_pos - begin_pos));
|
||||
if (os_version.find("\n") == string::npos) {
|
||||
return os_version;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return string();
|
||||
}
|
||||
#endif
|
||||
|
||||
Slice get_operating_system_version() {
|
||||
static string result = []() -> string {
|
||||
#if TD_DARWIN
|
||||
char version[256];
|
||||
size_t size = sizeof(version);
|
||||
string os_version;
|
||||
if (sysctlbyname("kern.osproductversion", version, &size, nullptr, 0) == 0) {
|
||||
os_version = trim(string(version, size));
|
||||
}
|
||||
if (os_version.empty()) {
|
||||
os_version = read_os_name("/System/Library/CoreServices/SystemVersion.plist",
|
||||
"<key>ProductUserVisibleVersion</key>\n\t<string>", "</string>\n");
|
||||
}
|
||||
if (!os_version.empty()) {
|
||||
os_version = " " + os_version;
|
||||
}
|
||||
|
||||
#if TD_DARWIN_IOS
|
||||
return "iOS" + os_version;
|
||||
#elif TD_DARWIN_TV_OS
|
||||
return "tvOS" + os_version;
|
||||
#elif TD_DARWIN_WATCH_OS
|
||||
return "watchOS" + os_version;
|
||||
#elif TD_DARWIN_MAC
|
||||
return "macOS" + os_version;
|
||||
#else
|
||||
return "Darwin" + os_version;
|
||||
#endif
|
||||
#elif TD_PORT_POSIX
|
||||
#if TD_ANDROID
|
||||
char version[PROP_VALUE_MAX + 1];
|
||||
int length = __system_property_get("ro.build.version.release", version);
|
||||
if (length > 0) {
|
||||
return "Android " + string(version, length);
|
||||
}
|
||||
#else
|
||||
#if TD_LINUX
|
||||
auto os_name = read_os_name("/etc/os-release", "PRETTY_NAME=\"", "\"\n");
|
||||
if (!os_name.empty()) {
|
||||
return os_name;
|
||||
}
|
||||
#endif
|
||||
|
||||
utsname name;
|
||||
int err = uname(&name);
|
||||
if (err == 0) {
|
||||
auto os_name = trim(PSTRING() << name.sysname << " " << name.release);
|
||||
if (!os_name.empty()) {
|
||||
return os_name;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
LOG(ERROR) << "Failed to identify OS name; use generic one";
|
||||
|
||||
#if TD_ANDROID
|
||||
return "Android";
|
||||
#elif TD_TIZEN
|
||||
return "Tizen";
|
||||
#elif TD_LINUX
|
||||
return "Linux";
|
||||
#elif TD_FREEBSD
|
||||
return "FreeBSD";
|
||||
#elif TD_OPENBSD
|
||||
return "OpenBSD";
|
||||
#elif TD_NETBSD
|
||||
return "NetBSD";
|
||||
#elif TD_CYGWIN
|
||||
return "Cygwin";
|
||||
#elif TD_EMSCRIPTEN
|
||||
return "Emscripten";
|
||||
#else
|
||||
return "Unix";
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
||||
auto handle = GetModuleHandle(L"ntdll.dll");
|
||||
if (handle != nullptr) {
|
||||
using RtlGetVersionPtr = LONG(WINAPI *)(PRTL_OSVERSIONINFOEXW);
|
||||
RtlGetVersionPtr RtlGetVersion = reinterpret_cast<RtlGetVersionPtr>(GetProcAddress(handle, "RtlGetVersion"));
|
||||
if (RtlGetVersion != nullptr) {
|
||||
RTL_OSVERSIONINFOEXW os_version_info = {};
|
||||
os_version_info.dwOSVersionInfoSize = sizeof(os_version_info);
|
||||
if (RtlGetVersion(&os_version_info) == 0) {
|
||||
auto major = os_version_info.dwMajorVersion;
|
||||
auto minor = os_version_info.dwMinorVersion;
|
||||
bool is_server = os_version_info.wProductType != VER_NT_WORKSTATION;
|
||||
|
||||
if (major == 10 && minor >= 0) {
|
||||
if (is_server) {
|
||||
return os_version_info.dwBuildNumber >= 17623 ? "Windows Server 2019" : "Windows Server 2016";
|
||||
}
|
||||
return "Windows 10";
|
||||
}
|
||||
if (major == 6 && minor == 3) {
|
||||
return is_server ? "Windows Server 2012 R2" : "Windows 8.1";
|
||||
}
|
||||
if (major == 6 && minor == 2) {
|
||||
return is_server ? "Windows Server 2012" : "Windows 8";
|
||||
}
|
||||
if (major == 6 && minor == 1) {
|
||||
return is_server ? "Windows Server 2008 R2" : "Windows 7";
|
||||
}
|
||||
if (major == 6 && minor == 0) {
|
||||
return is_server ? "Windows Server 2008" : "Windows Vista";
|
||||
}
|
||||
return is_server ? "Windows Server" : "Windows";
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif TD_WINRT
|
||||
return "Windows 10";
|
||||
#endif
|
||||
|
||||
LOG(ERROR) << "Failed to identify OS name; use generic one";
|
||||
return "Windows";
|
||||
#endif
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace td
|
9
tdutils/td/utils/port/uname.h
Normal file
9
tdutils/td/utils/port/uname.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "td/utils/Slice.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
Slice get_operating_system_version();
|
||||
|
||||
}
|
|
@ -16,44 +16,53 @@
|
|||
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "user.h"
|
||||
#if TD_LINUX
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include "td/utils/port/user.h"
|
||||
|
||||
#include "td/utils/port/config.h"
|
||||
|
||||
#if TD_PORT_POSIX
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#if TD_DARWIN || TD_FREEBSD || TD_NETBSD
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace td {
|
||||
|
||||
#if TD_LINUX
|
||||
td::Status change_user(td::Slice user) {
|
||||
struct passwd *pw;
|
||||
if (getuid() != 0 || geteuid() != 0) {
|
||||
return td::Status::PosixError(errno, "cannot setuid() as not root");
|
||||
}
|
||||
if ((pw = getpwnam(user.str().c_str())) == 0) {
|
||||
return td::Status::PosixError(errno, PSTRING() << "bad user '" << user << "'");
|
||||
Status change_user(CSlice username, CSlice groupname) {
|
||||
#if TD_PORT_POSIX
|
||||
passwd *pw = getpwnam(username.c_str());
|
||||
if (pw == nullptr) {
|
||||
return OS_ERROR(PSTRING() << "Can't find the user '" << username << "' to switch to");
|
||||
}
|
||||
uid_t uid = pw->pw_uid;
|
||||
gid_t gid = pw->pw_gid;
|
||||
if (setgroups(1, &gid) < 0) {
|
||||
return td::Status::PosixError(errno, "failed to clear supplementary groups list");
|
||||
if (setgroups(1, &gid) == -1) {
|
||||
return OS_ERROR("Failed to clear supplementary group list");
|
||||
}
|
||||
if (initgroups(user.str().c_str(), gid) != 0) {
|
||||
return td::Status::PosixError(errno, "failed to load groups of user");
|
||||
if (!groupname.empty()) {
|
||||
group *g = getgrnam(groupname.c_str());
|
||||
if (g == nullptr) {
|
||||
return OS_ERROR("Can't find the group to switch to");
|
||||
}
|
||||
gid = g->gr_gid;
|
||||
} else if (initgroups(username.c_str(), gid) == -1) {
|
||||
return OS_ERROR("Failed to load groups of user");
|
||||
}
|
||||
if (setgid(pw->pw_gid) < 0) {
|
||||
return td::Status::PosixError(errno, "failed to setgid()");
|
||||
if (setgid(gid) == -1) {
|
||||
return OS_ERROR("failed to set effective group ID");
|
||||
}
|
||||
if (setuid(pw->pw_uid) < 0) {
|
||||
return td::Status::PosixError(errno, "failed to setuid()");
|
||||
if (setuid(uid) == -1) {
|
||||
return OS_ERROR("failed to set effective user ID");
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
return Status::OK();
|
||||
#else
|
||||
td::Status change_user(td::Slice username) {
|
||||
return td::Status::Error("not implemented");
|
||||
}
|
||||
return Status::Error("Changing effective user is not supported");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
|
|
@ -16,14 +16,12 @@
|
|||
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/port/config.h"
|
||||
#include "td/utils/port/platform.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
td::Status change_user(td::Slice username);
|
||||
|
||||
Status change_user(CSlice username, CSlice groupname = CSlice());
|
||||
}
|
||||
|
|
|
@ -33,10 +33,7 @@ Result<std::wstring> to_wstring(CSlice slice) {
|
|||
return Status::Error("Wrong encoding");
|
||||
}
|
||||
|
||||
size_t wstring_len = 0;
|
||||
for (auto c : slice) {
|
||||
wstring_len += ((c & 0xc0) != 0x80) + ((c & 0xf8) == 0xf0);
|
||||
}
|
||||
size_t wstring_len = utf8_utf16_length(slice);
|
||||
|
||||
std::wstring result(wstring_len, static_cast<wchar_t>(0));
|
||||
if (wstring_len) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue