reworked the voice client connection part 1
This commit is contained in:
parent
b1f5620760
commit
a15eb9d25c
@ -90,50 +90,47 @@ bool AcknowledgeManager::process_acknowledge(uint8_t packet_type, uint16_t targe
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t AcknowledgeManager::execute_resend(const system_clock::time_point& now , std::chrono::system_clock::time_point &next_resend,std::deque<std::shared_ptr<Entry>>& buffers, string& error) {
|
||||
size_t resend_count{0};
|
||||
|
||||
vector<shared_ptr<Entry>> need_resend;
|
||||
void AcknowledgeManager::execute_resend(const system_clock::time_point& now , std::chrono::system_clock::time_point &next_resend,std::deque<std::shared_ptr<Entry>>& buffers) {
|
||||
vector<shared_ptr<Entry>> resend_failed;
|
||||
{
|
||||
bool cleanup{false};
|
||||
std::lock_guard lock{this->entry_lock};
|
||||
need_resend.reserve(this->entries.size());
|
||||
resend_failed.reserve(this->entries.size());
|
||||
|
||||
for (auto &entry : this->entries) {
|
||||
if(entry->acknowledged) {
|
||||
if(entry->next_resend + std::chrono::milliseconds{(int64_t) ceil(this->rto * 4)} <= now) { // Some resends are lost. So we just drop it after time
|
||||
if (entry->acknowledged) {
|
||||
if (entry->next_resend + std::chrono::milliseconds{(int64_t) ceil(this->rto * 4)} <= now) {
|
||||
/* Some resends are lost. So we just drop it after time */
|
||||
entry.reset();
|
||||
cleanup = true;
|
||||
}
|
||||
} else {
|
||||
if(entry->next_resend <= now) {
|
||||
entry->next_resend = now + std::chrono::milliseconds{(int64_t) std::min(ceil(this->rto), 1500.f)};
|
||||
need_resend.push_back(entry);
|
||||
//entry->resend_count++; /* this MUST be incremented by the result handler (resend may fails) */
|
||||
entry->send_count++;
|
||||
}
|
||||
if(next_resend > entry->next_resend)
|
||||
if (entry->next_resend <= now) {
|
||||
if (entry->resend_count > 15 && entry->first_send + seconds(15) < now) {
|
||||
resend_failed.push_back(std::move(entry)); /* transfer the ownership */
|
||||
cleanup = true;
|
||||
continue;
|
||||
} else {
|
||||
entry->next_resend =
|
||||
now + std::chrono::milliseconds{(int64_t) std::min(ceil(this->rto), 1500.f)};
|
||||
buffers.push_back(entry);
|
||||
//entry->resend_count++; /* this MUST be incremented by the result handler (resend may fails) */
|
||||
entry->send_count++;
|
||||
}
|
||||
}
|
||||
if (next_resend > entry->next_resend)
|
||||
next_resend = entry->next_resend;
|
||||
}
|
||||
}
|
||||
|
||||
if(cleanup) {
|
||||
if (cleanup) {
|
||||
this->entries.erase(std::remove_if(this->entries.begin(), this->entries.end(),
|
||||
[](const auto& entry) { return !entry; }), this->entries.end());
|
||||
[](const auto &entry) { return !entry; }), this->entries.end());
|
||||
}
|
||||
}
|
||||
|
||||
for(const auto& packet : need_resend) {
|
||||
if(packet->resend_count > 15 && packet->first_send + seconds(15) < now) { //FIXME configurable
|
||||
error = "Failed to receive acknowledge for packet " + to_string(packet->packet_full_id) + " of type " + PacketTypeInfo::fromid(packet->packet_type).name();
|
||||
return -1;
|
||||
}
|
||||
|
||||
resend_count++;
|
||||
buffers.push_back(packet);
|
||||
}
|
||||
|
||||
return resend_count;
|
||||
for(const auto& failed : resend_failed)
|
||||
this->callback_resend_failed(this->callback_data, failed);
|
||||
}
|
||||
|
||||
/* we're not taking the clock granularity into account because its nearly 1ms and it would only add more branches */
|
||||
|
@ -24,6 +24,8 @@ namespace ts::connection {
|
||||
void* packet_ptr;
|
||||
};
|
||||
|
||||
typedef void(*callback_resend_failed_t)(void* /* user data */, const std::shared_ptr<Entry>& /* entry */);
|
||||
|
||||
AcknowledgeManager();
|
||||
virtual ~AcknowledgeManager();
|
||||
|
||||
@ -33,11 +35,10 @@ namespace ts::connection {
|
||||
void process_packet(uint8_t /* packet type */, uint32_t /* full packet id */, void* /* packet ptr */, std::unique_ptr<threads::Future<bool>> /* ack listener */);
|
||||
bool process_acknowledge(uint8_t /* packet type */, uint16_t /* packet id */, std::string& /* error */);
|
||||
|
||||
ssize_t execute_resend(
|
||||
void execute_resend(
|
||||
const std::chrono::system_clock::time_point& /* now */,
|
||||
std::chrono::system_clock::time_point& /* next resend */,
|
||||
std::deque<std::shared_ptr<Entry>>& /* buffers to resend */,
|
||||
std::string& /* error */
|
||||
std::deque<std::shared_ptr<Entry>>& /* buffers to resend */
|
||||
);
|
||||
|
||||
[[nodiscard]] inline auto current_rto() const { return this->rto; }
|
||||
@ -45,6 +46,9 @@ namespace ts::connection {
|
||||
[[nodiscard]] inline auto current_rttvar() const { return this->rttvar; }
|
||||
|
||||
void(*destroy_packet)(void* /* packet */);
|
||||
|
||||
void* callback_data{nullptr};
|
||||
callback_resend_failed_t callback_resend_failed{[](auto, auto){}}; /* must be valid all the time */
|
||||
private:
|
||||
std::mutex entry_lock;
|
||||
std::deque<std::shared_ptr<Entry>> entries;
|
||||
|
@ -18,6 +18,7 @@ using namespace ts::protocol;
|
||||
|
||||
CryptHandler::CryptHandler() {
|
||||
memtrack::allocated<CryptHandler>(this);
|
||||
this->reset();
|
||||
}
|
||||
|
||||
CryptHandler::~CryptHandler() {
|
||||
|
@ -6,85 +6,85 @@
|
||||
#include <tomcrypt.h>
|
||||
#undef byte /* the macro byte gets defined by tomcrypt_macros. We have to undefine it */
|
||||
|
||||
namespace ts {
|
||||
namespace connection {
|
||||
class CryptHandler {
|
||||
enum Methode {
|
||||
TEAMSPEAK_3_1,
|
||||
TEAMSPEAK_3
|
||||
};
|
||||
struct KeyCache {
|
||||
uint16_t generation = 0xFFEF;
|
||||
union {
|
||||
struct {
|
||||
uint8_t key[16];
|
||||
uint8_t nonce[16];
|
||||
};
|
||||
uint8_t key_nonce[32];
|
||||
};
|
||||
};
|
||||
public:
|
||||
typedef std::array<uint8_t, 16> key_t;
|
||||
typedef std::array<uint8_t, 16> nonce_t;
|
||||
CryptHandler();
|
||||
~CryptHandler();
|
||||
|
||||
void reset();
|
||||
|
||||
//TeamSpeak old
|
||||
bool setupSharedSecret(const std::string& alpha, const std::string& beta, ecc_key* publicKey, ecc_key* ownKey, std::string &error);
|
||||
bool setupSharedSecret(const std::string& alpha, const std::string& beta, const std::string& sharedKey, std::string &error);
|
||||
|
||||
//TeamSpeak new
|
||||
bool setupSharedSecretNew(const std::string& alpha, const std::string& beta, const char privateKey[32], const char publicKey[32]);
|
||||
|
||||
/* mac must be 8 bytes long! */
|
||||
bool encrypt(
|
||||
const void* /* header */, size_t /* header length */,
|
||||
void* /* payload */, size_t /* payload length */,
|
||||
void* /* mac */,
|
||||
const key_t& /* key */, const nonce_t& /* nonce */,
|
||||
std::string& /* error */);
|
||||
|
||||
/* mac must be 8 bytes long! */
|
||||
bool decrypt(
|
||||
const void* /* header */, size_t /* header length */,
|
||||
void* /* payload */, size_t /* payload length */,
|
||||
const void* /* mac */,
|
||||
const key_t& /* key */, const nonce_t& /* nonce */,
|
||||
std::string& /* error */);
|
||||
|
||||
bool generate_key_nonce(bool /* to server */, uint8_t /* packet type */, uint16_t /* packet id */, uint16_t /* generation */, key_t& /* key */, nonce_t& /* nonce */);
|
||||
bool verify_encryption(const pipes::buffer_view& data, uint16_t packet_id, uint16_t generation);
|
||||
|
||||
inline void write_default_mac(void* buffer) {
|
||||
memcpy(buffer, this->current_mac, 8);
|
||||
}
|
||||
|
||||
static constexpr key_t default_key{'c', ':', '\\', 'w', 'i', 'n', 'd', 'o', 'w', 's', '\\', 's', 'y', 's', 't', 'e'}; //c:\windows\syste
|
||||
static constexpr nonce_t default_nonce{'m', '\\', 'f', 'i', 'r', 'e', 'w', 'a', 'l', 'l', '3', '2', '.', 'c', 'p', 'l'}; //m\firewall32.cpl
|
||||
private:
|
||||
static constexpr char default_mac[8] = {'T', 'S', '3', 'I', 'N', 'I', 'T', '1'}; //TS3INIT1
|
||||
|
||||
|
||||
bool generate_key_nonce(protocol::BasicPacket* packet, bool use_default, uint8_t(&)[16] /* key */, uint8_t(&)[16] /* nonce */);
|
||||
|
||||
|
||||
//The default key and nonce
|
||||
bool useDefaultChipherKeyNonce = true;
|
||||
|
||||
/* for the old protocol SHA1 length for the new 64 bytes */
|
||||
uint8_t iv_struct[64];
|
||||
uint8_t iv_struct_length = 0;
|
||||
|
||||
uint8_t current_mac[8];
|
||||
|
||||
std::mutex cache_key_lock;
|
||||
std::array<KeyCache, protocol::PACKET_MAX> cache_key_client;
|
||||
std::array<KeyCache, protocol::PACKET_MAX> cache_key_server;
|
||||
|
||||
static_assert(sizeof(current_mac) == sizeof(default_mac), "invalid mac");
|
||||
static_assert(sizeof(iv_struct) == 64, "invalid iv struct");
|
||||
namespace ts::connection {
|
||||
class CryptHandler {
|
||||
enum Methode {
|
||||
TEAMSPEAK_3_1,
|
||||
TEAMSPEAK_3
|
||||
};
|
||||
}
|
||||
struct KeyCache {
|
||||
uint16_t generation = 0xFFEF;
|
||||
union {
|
||||
struct {
|
||||
uint8_t key[16];
|
||||
uint8_t nonce[16];
|
||||
};
|
||||
uint8_t key_nonce[32];
|
||||
};
|
||||
};
|
||||
public:
|
||||
typedef std::array<uint8_t, 16> key_t;
|
||||
typedef std::array<uint8_t, 16> nonce_t;
|
||||
CryptHandler();
|
||||
~CryptHandler();
|
||||
|
||||
void reset();
|
||||
|
||||
//TeamSpeak old
|
||||
bool setupSharedSecret(const std::string& alpha, const std::string& beta, ecc_key* publicKey, ecc_key* ownKey, std::string &error);
|
||||
bool setupSharedSecret(const std::string& alpha, const std::string& beta, const std::string& sharedKey, std::string &error);
|
||||
|
||||
//TeamSpeak new
|
||||
bool setupSharedSecretNew(const std::string& alpha, const std::string& beta, const char privateKey[32], const char publicKey[32]);
|
||||
|
||||
/* mac must be 8 bytes long! */
|
||||
bool encrypt(
|
||||
const void* /* header */, size_t /* header length */,
|
||||
void* /* payload */, size_t /* payload length */,
|
||||
void* /* mac */,
|
||||
const key_t& /* key */, const nonce_t& /* nonce */,
|
||||
std::string& /* error */);
|
||||
|
||||
/* mac must be 8 bytes long! */
|
||||
bool decrypt(
|
||||
const void* /* header */, size_t /* header length */,
|
||||
void* /* payload */, size_t /* payload length */,
|
||||
const void* /* mac */,
|
||||
const key_t& /* key */, const nonce_t& /* nonce */,
|
||||
std::string& /* error */);
|
||||
|
||||
bool generate_key_nonce(bool /* to server */, uint8_t /* packet type */, uint16_t /* packet id */, uint16_t /* generation */, key_t& /* key */, nonce_t& /* nonce */);
|
||||
bool verify_encryption(const pipes::buffer_view& data, uint16_t packet_id, uint16_t generation);
|
||||
|
||||
inline void write_default_mac(void* buffer) {
|
||||
memcpy(buffer, this->current_mac, 8);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool encryption_initialized() const { return !this->useDefaultChipherKeyNonce; }
|
||||
|
||||
static constexpr key_t kDefaultKey{'c', ':', '\\', 'w', 'i', 'n', 'd', 'o', 'w', 's', '\\', 's', 'y', 's', 't', 'e'}; //c:\windows\syste
|
||||
static constexpr nonce_t kDefaultNonce{'m', '\\', 'f', 'i', 'r', 'e', 'w', 'a', 'l', 'l', '3', '2', '.', 'c', 'p', 'l'}; //m\firewall32.cpl
|
||||
private:
|
||||
static constexpr char default_mac[8] = {'T', 'S', '3', 'I', 'N', 'I', 'T', '1'}; //TS3INIT1
|
||||
|
||||
|
||||
bool generate_key_nonce(protocol::BasicPacket* packet, bool use_default, uint8_t(&)[16] /* key */, uint8_t(&)[16] /* nonce */);
|
||||
|
||||
|
||||
//The default key and nonce
|
||||
bool useDefaultChipherKeyNonce = true;
|
||||
|
||||
/* for the old protocol SHA1 length for the new 64 bytes */
|
||||
uint8_t iv_struct[64];
|
||||
uint8_t iv_struct_length = 0;
|
||||
|
||||
uint8_t current_mac[8];
|
||||
|
||||
std::mutex cache_key_lock;
|
||||
std::array<KeyCache, protocol::PACKET_MAX> cache_key_client;
|
||||
std::array<KeyCache, protocol::PACKET_MAX> cache_key_server;
|
||||
|
||||
static_assert(sizeof(current_mac) == sizeof(default_mac), "invalid mac");
|
||||
static_assert(sizeof(iv_struct) == 64, "invalid iv struct");
|
||||
};
|
||||
}
|
@ -129,17 +129,25 @@ namespace ts {
|
||||
}
|
||||
|
||||
inline bool insert_index(size_type index, E&& entry) {
|
||||
return insert_index2(index, std::forward<E>(entry)) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index
|
||||
* @return -2 duplicated entry | -1 underflow | 0 success | 1 overflow
|
||||
*/
|
||||
inline int insert_index2(size_type index, E&& entry) {
|
||||
size_t relative_index = 0;
|
||||
if(!this->calculate_index(index, relative_index))
|
||||
return false;
|
||||
return index < this->current_index() ? -1 : 1;
|
||||
|
||||
auto& slot = this->index(relative_index);
|
||||
if(slot.flag_set)
|
||||
return false;
|
||||
return -2;
|
||||
|
||||
slot.entry = std::forward<E>(entry);
|
||||
slot.flag_set = true;
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline size_t capacity() { return this->_capacity; }
|
||||
@ -209,5 +217,11 @@ namespace ts {
|
||||
std::recursive_timed_mutex buffer_lock;
|
||||
std::recursive_timed_mutex execute_lock;
|
||||
};
|
||||
|
||||
template <typename E, uint32_t SIZE = 32, typename PTR_TYPE = std::shared_ptr<E>>
|
||||
class FullPacketRingBuffer : public RingBuffer<PTR_TYPE, SIZE, uint32_t> {
|
||||
public:
|
||||
std::mutex buffer_lock;
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user