Some minor changes
This commit is contained in:
parent
7822d20efe
commit
e39f01bde5
@ -1 +1 @@
|
||||
Subproject commit 2c928229b1aab0306a02d2b7820fd93f3a3623b9
|
||||
Subproject commit 6b6e8774b8cb37158d6ee09658559e7dff4dd1c3
|
@ -4,6 +4,7 @@
|
||||
#include <event2/thread.h>
|
||||
#include <random>
|
||||
#include <ed25519/ed25519.h>
|
||||
#include <misc/base64.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
@ -23,12 +24,43 @@ using namespace license;
|
||||
inline bool isValid() { return (end.time_since_epoch().count() == 0 || std::chrono::system_clock::now() < this->end); }
|
||||
};
|
||||
*/
|
||||
|
||||
std::array<uint8_t, 195> intermediate_key{0x02, 0x00, 0x2d, 0x6b, 0xe3, 0x4d, 0x3c, 0xbb, 0x19, 0x1e, 0x46, 0x25, 0x72, 0x22, 0xa3, 0x53, 0x6d, 0x2d, 0xc3, 0xd1, 0x2c, 0xc8, 0xea, 0xf2, 0xf8, 0xe5, 0xd5, 0x0f, 0x6c, 0x7f, 0xeb, 0x63, 0x8a, 0xc4, 0x37, 0xb2, 0x33, 0x5e, 0x06, 0x31, 0xcf, 0x2c, 0xc6, 0xbe, 0x5e, 0x9c, 0xf1, 0xe6, 0xb3, 0xc3, 0x69, 0xd7, 0xf0, 0x05, 0x90, 0x2f, 0x65, 0x03, 0x60, 0x12, 0xa0, 0x20, 0x83, 0xe2, 0x6b, 0x4f, 0x46, 0xab, 0xfd, 0xa6, 0x22, 0x0b, 0x11, 0x9a, 0x34, 0xfe, 0x7b, 0xa3, 0x1b, 0x12, 0xce, 0x30, 0xf7, 0x0a, 0x32, 0x26, 0x23, 0x10, 0xfe, 0x58, 0xb6, 0xc7, 0x5d, 0x3d, 0xc6, 0x14, 0xdc, 0x10, 0xa0, 0xc0, 0x78, 0x10, 0x45, 0x41, 0x36, 0x1a, 0x1c, 0x9f, 0x60, 0x25, 0xd9, 0x69, 0xc9, 0x0b, 0xb7, 0xb4, 0x64, 0xab, 0x6c, 0x22, 0xff, 0xaf, 0x86, 0x26, 0x94, 0xcc, 0x7f, 0x59, 0x52, 0xa3, 0x56, 0x7f, 0x3e, 0x86, 0x04, 0x4c, 0xe0, 0x0e, 0xb3, 0xb1, 0x23, 0x51, 0xf7, 0xf0, 0x14, 0x5d, 0xfd, 0x48, 0xfb, 0x16, 0xe6, 0xc6, 0xca, 0xf2, 0x8d, 0xc8, 0xce, 0xf1, 0x2b, 0x12, 0x9e, 0xd1, 0x7a, 0x80, 0x3a, 0x9b, 0x46, 0xe7, 0xca, 0x34, 0x04, 0xae, 0x3d, 0x12, 0xcd, 0x4a, 0xc6, 0xe1, 0xf1, 0xe4, 0xd8, 0xca, 0x68, 0x36, 0xd3, 0x94, 0x0d, 0xef, 0x93, 0x86, 0xb9, 0x3a, 0xa4, 0x10, 0x52};
|
||||
int main(int ac, char** av){
|
||||
auto state = evthread_use_pthreads();
|
||||
assert(state == 0);
|
||||
string error;
|
||||
uint8_t errc = 0;
|
||||
|
||||
#if 0
|
||||
std::array<uint8_t, 32> prv_key{};
|
||||
auto license = v2::License::create({}, prv_key);
|
||||
assert(license->private_data_editable());
|
||||
|
||||
license->push_entry<v2::hierarchy::Intermediate>(system_clock::now(), system_clock::now() + hours{24 * 365 * 1000}, "TeaSpeak (Test)");
|
||||
assert(license->write_private_data({0}));
|
||||
error = license->write(errc);
|
||||
assert(errc == 0);
|
||||
|
||||
cout << "Intermediate: " << hex;
|
||||
for(size_t index = 0; index < error.length(); index++) {
|
||||
uint8_t e = error[index];
|
||||
cout << " 0x" << (e <= 0xF ? "0" : "") << (uint32_t) e << ",";
|
||||
}
|
||||
cout << endl;
|
||||
cout << "Intermediate: " << base64::encode(error) << endl;
|
||||
|
||||
#endif
|
||||
auto license = v2::License::read(intermediate_key.data(), intermediate_key.size(), errc);
|
||||
|
||||
license->push_entry<v2::hierarchy::Server>(system_clock::now(), system_clock::now() + hours{24 * 365 * 1000}, "TeaSpeak Official server", "contact@teaspeak.de");
|
||||
assert(license->write_private_data({0}));
|
||||
error = license->write(errc);
|
||||
assert(errc == 0);
|
||||
__asm__("nop");
|
||||
cout << "Errc: " << errc << endl;
|
||||
cout << "Write: " << base64::encode(error) << endl;
|
||||
#if 0
|
||||
std::array<uint8_t, 32> private_key, public_key;
|
||||
|
||||
std::random_device rd;
|
||||
@ -51,6 +83,7 @@ int main(int ac, char** av){
|
||||
cout << endl;
|
||||
|
||||
return true;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
srand(system_clock::now().time_since_epoch().count());
|
||||
|
@ -119,7 +119,6 @@ namespace license::v2 {
|
||||
}
|
||||
|
||||
std::shared_ptr<License> License::create(const std::vector<std::shared_ptr<const license::v2::HierarchyEntry>> &hierarchy, const std::array<uint8_t, 32> &prv_key) {
|
||||
assert(!hierarchy.empty());
|
||||
auto result = shared_ptr<License>(new License{});
|
||||
|
||||
result->_version = 2;
|
||||
@ -175,20 +174,24 @@ namespace license::v2 {
|
||||
|
||||
/* "decode" the data */
|
||||
{
|
||||
auto index = 0;
|
||||
while(index + 4 < decoded_buffer_length) {
|
||||
auto& memory = *(uint32_t*) (&*decoded_buffer + index);
|
||||
auto index = sizeof(header);
|
||||
auto index_decoded = 0;
|
||||
while(index + 4 < length) {
|
||||
auto& memory = *(uint32_t*) (&*decoded_buffer + index_decoded);
|
||||
memory = *(uint32_t*) (buffer + index);
|
||||
memory ^= (uint32_t) crypt_key_gen();
|
||||
index += 4;
|
||||
index_decoded += 4;
|
||||
}
|
||||
while(index < decoded_buffer_length) {
|
||||
auto& memory = *(uint8_t*) (&*decoded_buffer + index);
|
||||
while(index < length) {
|
||||
auto& memory = *(uint8_t*) (&*decoded_buffer + index_decoded);
|
||||
memory = *(uint8_t*) (buffer + index);
|
||||
memory ^= (uint8_t) crypt_key_gen();
|
||||
index++;
|
||||
index_decoded++;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&body_header, &*decoded_buffer, sizeof(body_header));
|
||||
if(decoded_buffer_length < sizeof(body_header) + body_header.length_hierarchy + body_header.length_private_data) {
|
||||
error = 2; /* buffer too small */
|
||||
@ -243,7 +246,7 @@ namespace license::v2 {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string License::write(int &error) {
|
||||
std::string License::write(uint8_t &error) {
|
||||
if(!this->private_data || !this->private_buffer_length) {
|
||||
error = 2; /* missing private data */
|
||||
return "";
|
||||
@ -278,8 +281,8 @@ namespace license::v2 {
|
||||
error = 3; /* failed to write hierarchy */
|
||||
return "";
|
||||
}
|
||||
body_header.length_hierarchy = offset - begin_offset;
|
||||
|
||||
body_header.length_hierarchy = offset - begin_offset;
|
||||
digest::sha1((char*) &*buffer + begin_offset, body_header.length_hierarchy, body_header.checksum_hierarchy);
|
||||
}
|
||||
|
||||
@ -335,6 +338,8 @@ namespace license::v2 {
|
||||
}
|
||||
|
||||
bool License::write_private_data(const LicensePrivateWriteOptions& write_options) {
|
||||
if(this->_hierarchy.empty()) return false;
|
||||
|
||||
uint8_t private_key[64]; //ed25519_sign requires 64 bytes (may it expects a public key in front?)
|
||||
if(!this->private_data->calculate_private_key(private_key, this->_hierarchy.size() - 1))
|
||||
return false;
|
||||
@ -409,7 +414,7 @@ namespace license::v2 {
|
||||
|
||||
std::array<uint8_t, 32> result{};
|
||||
ge_p3_tobytes((uint8_t*) result.data(), &parent_key);
|
||||
return {};
|
||||
return result;
|
||||
}
|
||||
|
||||
bool License::push_entry(const std::shared_ptr<const HierarchyEntry> &entry, size_t* index) {
|
||||
@ -542,7 +547,7 @@ namespace license::v2 {
|
||||
bool LicensePrivate::write(uint8_t *buffer, size_t &offset, size_t length, const LicensePrivateWriteOptions& options) {
|
||||
if(options.precalculated_key_index < -1) {
|
||||
if(buffer) {
|
||||
if((offset + 2) < length) return false;
|
||||
if((offset + 2) > length) return false;
|
||||
*(buffer + offset++) = 0; /* no precalculated private key */
|
||||
*(buffer + offset++) = 0; /* no raw private keys */
|
||||
} else {
|
||||
@ -553,23 +558,24 @@ namespace license::v2 {
|
||||
if(index < 0) return false; /* we will NEVER write the root key */
|
||||
|
||||
if(buffer) {
|
||||
if((offset + 2 + 32) < length) return false;
|
||||
if((offset + 2 + 32) > length) return false;
|
||||
*(buffer + offset++) = 1;
|
||||
{
|
||||
*(buffer + offset++) = index;
|
||||
|
||||
if(!this->calculate_private_key(buffer + offset, index))
|
||||
return false;
|
||||
offset += 32;
|
||||
}
|
||||
|
||||
if((offset + 1) < length) return false;
|
||||
if((offset + 1) > length) return false;
|
||||
auto& private_key_count = *(buffer + offset++);
|
||||
private_key_count = 0;
|
||||
for(auto& [key_index, key] : this->private_keys) {
|
||||
if(key_index <= index)
|
||||
continue;
|
||||
|
||||
if((offset + 1 + key.size()) < length) return false;
|
||||
if((offset + 1 + key.size()) > length) return false;
|
||||
*(buffer + offset++) = key_index;
|
||||
memcpy(buffer + offset, key.data(), key.size());
|
||||
|
||||
@ -592,12 +598,12 @@ namespace license::v2 {
|
||||
}
|
||||
|
||||
if(buffer) {
|
||||
if((offset + 4) < length) return false;
|
||||
if((offset + 4) > length) return false;
|
||||
*(uint32_t*) (buffer + offset) = this->meta_data.size();
|
||||
offset += 4;
|
||||
|
||||
for(auto& [key, value] : this->meta_data) {
|
||||
if((offset + 3 + key.length() + value.length()) < length) return false;
|
||||
if((offset + 3 + key.length() + value.length()) > length) return false;
|
||||
|
||||
*(buffer + offset++) = key.length();
|
||||
*(uint16_t*)(buffer + offset) = value.length();
|
||||
@ -625,7 +631,7 @@ namespace license::v2 {
|
||||
auto hierarchy = handle->hierarchy();
|
||||
|
||||
auto base_index = this->precalculated_private_key_index;
|
||||
if(base_index >= hierarchy.size()) return false;
|
||||
if(base_index >= (int64_t) hierarchy.size()) return false;
|
||||
if(base_index < -1) return true; /* means we don't have a private key */
|
||||
|
||||
while(base_index < hierarchy.size()) {
|
||||
@ -635,12 +641,12 @@ namespace license::v2 {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LicensePrivate::private_key_calculable(uint8_t index) const {
|
||||
bool LicensePrivate::private_key_calculable(int index) const {
|
||||
auto handle = this->_handle.lock();
|
||||
if(!handle) return false;
|
||||
|
||||
auto hierarchy = handle->hierarchy();
|
||||
if(index >= hierarchy.size()) return false;
|
||||
if(index >= (int64_t) hierarchy.size()) return false;
|
||||
|
||||
|
||||
auto base_index = this->precalculated_private_key_index;
|
||||
@ -726,6 +732,9 @@ namespace license::v2 {
|
||||
if(!result->allocate_read_body(body_length)) return nullptr;
|
||||
|
||||
if(body_length > 0) {
|
||||
result->allocate_read_body(body_length);
|
||||
if(!result->read_body) return nullptr;
|
||||
result->read_body_length = body_length;
|
||||
memcpy(result->read_body, buffer + offset, body_length);
|
||||
offset += body_length;
|
||||
}
|
||||
@ -779,11 +788,11 @@ namespace license::v2 {
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t length = 42 + this->read_body_length, offset = 0;
|
||||
auto buffer = (uint8_t*) malloc(length);
|
||||
size_t length = 43 + this->read_body_length, offset = 0;
|
||||
auto buffer = unique_ptr<uint8_t, decltype(::free)*>((uint8_t*) malloc(length), ::free);
|
||||
if(!buffer) return false;
|
||||
if(this->write(buffer, offset, length)) {
|
||||
digest::sha512((char*) buffer, length, this->_hash.data());
|
||||
if(this->write(&*buffer, offset, length)) {
|
||||
digest::sha512((char*) &*buffer, length, this->_hash.data());
|
||||
this->_hash_set = true;
|
||||
}
|
||||
|
||||
@ -800,14 +809,53 @@ namespace license::v2 {
|
||||
|
||||
std::shared_ptr<const HierarchyEntry> Intermediate::create(const uint8_t *pub_key, const std::chrono::system_clock::time_point &begin, const std::chrono::system_clock::time_point & end, const std::string &description) {
|
||||
assert(description.size() < 256);
|
||||
auto result = shared_ptr<HierarchyEntry>(new HierarchyEntry{hierarchy::Intermediate::type, pub_key, begin, end});
|
||||
auto buffer_length = description.size() + 1;
|
||||
|
||||
if(!result || !result->allocate_read_body(description.size() + 1)) return nullptr;
|
||||
memcpy(result->read_body + 1, description.data(), description.length());
|
||||
*result->read_body = (uint8_t) description.length();
|
||||
uint8_t* buffer;
|
||||
auto result = BodyInterpreter::_create<Intermediate>(pub_key, begin, end, buffer_length, buffer);
|
||||
if(!result) return nullptr;
|
||||
|
||||
memcpy(buffer + 1, description.data(), description.length());
|
||||
*buffer = (uint8_t) description.length();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Server::has_username() {
|
||||
return *(this->_memory + 1) > 0;
|
||||
}
|
||||
|
||||
std::string_view Server::contact_email() {
|
||||
return {(const char*) this->_memory + 2, *this->_memory};
|
||||
}
|
||||
|
||||
std::string_view Server::username() {
|
||||
return {(const char*) this->_memory + 2 + *this->_memory, *(this->_memory + 1)};
|
||||
}
|
||||
|
||||
std::shared_ptr<const HierarchyEntry> Server::create(const uint8_t *pub_key, const std::chrono::system_clock::time_point &begin, const std::chrono::system_clock::time_point & end, const std::string &email, const std::optional<std::string> &username) {
|
||||
assert(email.size() < 256);
|
||||
assert(!username.has_value() || username->size() < 256);
|
||||
auto buffer_length = 2 + email.size() + (username.has_value() ? username->length() : 0);
|
||||
|
||||
uint8_t* buffer;
|
||||
auto result = BodyInterpreter::_create<Intermediate>(pub_key, begin, end, buffer_length, buffer);
|
||||
if(!result) return nullptr;
|
||||
|
||||
memcpy(buffer + 2, email.data(), email.length());
|
||||
*buffer = (uint8_t) email.length();
|
||||
|
||||
if(username.has_value())
|
||||
memcpy(buffer + 2 + email.length(), username->data(), username->length());
|
||||
*(buffer + 1) = (uint8_t) (username.has_value() ? username->length() : 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<const HierarchyEntry> Ephemeral::create(const uint8_t *pub_key, const std::chrono::system_clock::time_point &begin, const std::chrono::system_clock::time_point & end) {
|
||||
uint8_t* buffer;
|
||||
return BodyInterpreter::_create<Ephemeral>(pub_key, begin, end, 0, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static int test() {
|
||||
|
@ -84,7 +84,7 @@ namespace license {
|
||||
|
||||
std::array<uint8_t, 32> generate_public_key(const uint8_t* /* public key root */, int /* length */ = -1) const;
|
||||
|
||||
std::string write(int& /* error */);
|
||||
std::string write(uint8_t& /* error */);
|
||||
|
||||
bool private_data_editable() const;
|
||||
bool write_private_data(const LicensePrivateWriteOptions& /* write options */);
|
||||
@ -128,7 +128,7 @@ namespace license {
|
||||
void register_raw_private_key(uint8_t /* index */, const uint8_t* /* key */);
|
||||
bool has_raw_private_key(uint8_t /* index */) const;
|
||||
|
||||
bool private_key_calculable(uint8_t /* index */) const;
|
||||
bool private_key_calculable(int /* index */) const;
|
||||
bool calculate_private_key(uint8_t* /* response */, uint8_t /* index */) const;
|
||||
private:
|
||||
std::weak_ptr<License> _handle;
|
||||
@ -141,11 +141,11 @@ namespace license {
|
||||
};
|
||||
|
||||
namespace hierarchy {
|
||||
struct Intermediate;
|
||||
struct BodyInterpreter;
|
||||
}
|
||||
|
||||
struct HierarchyEntry {
|
||||
friend struct hierarchy::Intermediate;
|
||||
friend struct hierarchy::BodyInterpreter;
|
||||
public:
|
||||
~HierarchyEntry();
|
||||
|
||||
@ -172,12 +172,12 @@ namespace license {
|
||||
|
||||
template <typename I>
|
||||
inline I interpret_as() const {
|
||||
assert(this->interpret_as<I>());
|
||||
assert(this->interpretable_as<I>());
|
||||
return I{this->read_body, this->read_body_length};
|
||||
}
|
||||
|
||||
template <typename I>
|
||||
inline bool interpretable_as() const { return I::type == this->_entry_type; }
|
||||
inline bool interpretable_as() const { return I::_type == this->_entry_type; }
|
||||
|
||||
inline bool hash(uint8_t* /* hash result [64] */) const;
|
||||
protected:
|
||||
@ -207,20 +207,54 @@ namespace license {
|
||||
};
|
||||
|
||||
namespace hierarchy {
|
||||
struct type {
|
||||
enum value : uint8_t {
|
||||
Intermediate = 1,
|
||||
Server = 2,
|
||||
Ephemeral = 8
|
||||
};
|
||||
|
||||
static constexpr const char* name(const value& value) {
|
||||
switch (value) {
|
||||
case Intermediate:
|
||||
return "Intermediate";
|
||||
case Server:
|
||||
return "Server";
|
||||
case Ephemeral:
|
||||
return "Ephemeral";
|
||||
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
};
|
||||
struct BodyInterpreter {
|
||||
public:
|
||||
BodyInterpreter() = delete;
|
||||
|
||||
protected:
|
||||
template <typename T>
|
||||
static std::shared_ptr<HierarchyEntry> _create(
|
||||
const uint8_t *pub_key,
|
||||
const std::chrono::system_clock::time_point &begin,
|
||||
const std::chrono::system_clock::time_point &end,
|
||||
size_t buffer_size, uint8_t*& buffer_ptr
|
||||
) {
|
||||
auto result = std::shared_ptr<HierarchyEntry>(new HierarchyEntry{T::_type, pub_key, begin, end});
|
||||
if(!result || !result->allocate_read_body(buffer_size)) return nullptr;
|
||||
result->read_body_length = buffer_size;
|
||||
buffer_ptr = result->read_body;
|
||||
return result;
|
||||
}
|
||||
|
||||
BodyInterpreter(const uint8_t* memory, size_t length) { this->_memory = memory; this->_length = length; }
|
||||
const uint8_t* _memory = nullptr;
|
||||
size_t _length = 0;
|
||||
};
|
||||
|
||||
struct Intermediate : public BodyInterpreter {
|
||||
friend struct HierarchyEntry;
|
||||
public:
|
||||
static constexpr uint8_t type = 1;
|
||||
static constexpr uint8_t _type = type::Intermediate;
|
||||
static std::shared_ptr<const HierarchyEntry> create(
|
||||
const uint8_t* /* public key */,
|
||||
const std::chrono::system_clock::time_point& /* begin */,
|
||||
@ -232,6 +266,38 @@ namespace license {
|
||||
private:
|
||||
Intermediate(const uint8_t* memory, size_t length) : BodyInterpreter(memory, length) {}
|
||||
};
|
||||
|
||||
struct Server : public BodyInterpreter {
|
||||
public:
|
||||
static constexpr uint8_t _type = type::Server;
|
||||
static std::shared_ptr<const HierarchyEntry> create(
|
||||
const uint8_t* /* public key */,
|
||||
const std::chrono::system_clock::time_point& /* begin */,
|
||||
const std::chrono::system_clock::time_point& /* end */,
|
||||
|
||||
const std::string& /* email */,
|
||||
const std::optional<std::string>& /* value */
|
||||
);
|
||||
|
||||
std::string_view contact_email();
|
||||
|
||||
bool has_username();
|
||||
std::string_view username();
|
||||
private:
|
||||
Server(const uint8_t* memory, size_t length) : BodyInterpreter(memory, length) {}
|
||||
};
|
||||
|
||||
struct Ephemeral : public BodyInterpreter {
|
||||
public:
|
||||
static constexpr uint8_t _type = type::Ephemeral;
|
||||
static std::shared_ptr<const HierarchyEntry> create(
|
||||
const uint8_t* /* public key */,
|
||||
const std::chrono::system_clock::time_point& /* begin */,
|
||||
const std::chrono::system_clock::time_point& /* end */
|
||||
);
|
||||
private:
|
||||
Ephemeral(const uint8_t* memory, size_t length) : BodyInterpreter(memory, length) {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,7 +160,7 @@ bool ConnectedClient::notifyClientPermList(ClientDbId cldbid, const std::shared_
|
||||
bool ConnectedClient::notifyChannelGroupList() {
|
||||
Command cmd(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifychannelgrouplist" : "");
|
||||
int index = 0;
|
||||
for (const auto &group : (this->server ? this->server->groups : serverInstance->getGroupManager().get())->availableChannelGroups(false)) {
|
||||
for (const auto &group : (this->server ? this->server->groups : serverInstance->getGroupManager().get())->availableChannelGroups(true)) {
|
||||
if(group->target() == GroupTarget::GROUPTARGET_CHANNEL) {
|
||||
cmd[index]["cgid"] = group->groupId();
|
||||
} else {
|
||||
|
@ -106,6 +106,19 @@ void VoiceIOManager::adjustExecutors(size_t size) {
|
||||
}
|
||||
}
|
||||
|
||||
IOEventLoop::~IOEventLoop() {
|
||||
if(this->executor.joinable()) {
|
||||
auto handle = this->executor.native_handle();
|
||||
timespec timeout{};
|
||||
clock_gettime(CLOCK_REALTIME, &timeout);
|
||||
timeout.tv_sec += 5;
|
||||
auto join_result = pthread_timedjoin_np(handle, nullptr, &timeout);
|
||||
if(join_result == EBUSY)
|
||||
logError(LOG_INSTANCE, "Failed to shutdown IO event loop. Error: {}", join_result);
|
||||
}
|
||||
assert(!this->executor.joinable());
|
||||
}
|
||||
|
||||
/**
|
||||
* @warning executor lock must be locked!
|
||||
*/
|
||||
|
@ -53,16 +53,7 @@ namespace ts {
|
||||
|
||||
struct IOEventLoop {
|
||||
IOEventLoop() = default;
|
||||
~IOEventLoop() {
|
||||
if(this->executor.joinable()) {
|
||||
auto handle = this->executor.native_handle();
|
||||
timespec timeout{};
|
||||
clock_gettime(CLOCK_REALTIME, &timeout);
|
||||
timeout.tv_sec += 5;
|
||||
auto join_result = pthread_timedjoin_np(handle, nullptr, &timeout);
|
||||
}
|
||||
assert(!this->executor.joinable());
|
||||
}
|
||||
~IOEventLoop();
|
||||
|
||||
int bound_thread = -1; /* -1 represents that this loop is bound to no thread at all */
|
||||
|
||||
|
2
shared
2
shared
@ -1 +1 @@
|
||||
Subproject commit cb73d9df3258eaf59e4799c9e54d5f865e891734
|
||||
Subproject commit e30c03029fb2be1a84a2706cf9bdd4f28cce9051
|
Loading…
x
Reference in New Issue
Block a user