diff --git a/src/protocol/AcknowledgeManager.cpp b/src/protocol/AcknowledgeManager.cpp index 249ffae..fd41755 100644 --- a/src/protocol/AcknowledgeManager.cpp +++ b/src/protocol/AcknowledgeManager.cpp @@ -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>& buffers, string& error) { - size_t resend_count{0}; - - vector> need_resend; +void AcknowledgeManager::execute_resend(const system_clock::time_point& now , std::chrono::system_clock::time_point &next_resend,std::deque>& buffers) { + vector> 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 */ diff --git a/src/protocol/AcknowledgeManager.h b/src/protocol/AcknowledgeManager.h index 28a892d..e407f5d 100644 --- a/src/protocol/AcknowledgeManager.h +++ b/src/protocol/AcknowledgeManager.h @@ -24,6 +24,8 @@ namespace ts::connection { void* packet_ptr; }; + typedef void(*callback_resend_failed_t)(void* /* user data */, const std::shared_ptr& /* 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> /* 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>& /* buffers to resend */, - std::string& /* error */ + std::deque>& /* 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> entries; diff --git a/src/protocol/CryptHandler.cpp b/src/protocol/CryptHandler.cpp index 98b4d66..ef87502 100644 --- a/src/protocol/CryptHandler.cpp +++ b/src/protocol/CryptHandler.cpp @@ -18,6 +18,7 @@ using namespace ts::protocol; CryptHandler::CryptHandler() { memtrack::allocated(this); + this->reset(); } CryptHandler::~CryptHandler() { diff --git a/src/protocol/CryptHandler.h b/src/protocol/CryptHandler.h index b241c14..f2883af 100644 --- a/src/protocol/CryptHandler.h +++ b/src/protocol/CryptHandler.h @@ -6,85 +6,85 @@ #include #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 key_t; - typedef std::array 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 cache_key_client; - std::array 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 key_t; + typedef std::array 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 cache_key_client; + std::array cache_key_server; + + static_assert(sizeof(current_mac) == sizeof(default_mac), "invalid mac"); + static_assert(sizeof(iv_struct) == 64, "invalid iv struct"); + }; } \ No newline at end of file diff --git a/src/protocol/ringbuffer.h b/src/protocol/ringbuffer.h index b592e73..217e0f0 100644 --- a/src/protocol/ringbuffer.h +++ b/src/protocol/ringbuffer.h @@ -129,17 +129,25 @@ namespace ts { } inline bool insert_index(size_type index, E&& entry) { + return insert_index2(index, std::forward(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(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 > + class FullPacketRingBuffer : public RingBuffer { + public: + std::mutex buffer_lock; + }; } } \ No newline at end of file