#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include "VoiceClient.h" #include "protocol/AcknowledgeManager.h" #include #include "./PacketStatistics.h" #include "./PacketDecoder.h" #include "./PacketEncoder.h" //#define LOG_ACK_SYSTEM #ifdef LOG_ACK_SYSTEM #define LOG_AUTO_ACK_REQUEST #define LOG_AUTO_ACK_RESPONSE #define LOG_PKT_RESEND #endif //#define PKT_LOG_PING namespace ts { namespace server { class VoiceClient; class VoiceServer; class POWHandler; } namespace connection { class VoiceClientConnection { friend class AcknowledgeManager; friend class server::VoiceServer; friend class server::VoiceClient; friend class server::POWHandler; using PacketDecoder = server::server::udp::PacketDecoder; using PacketEncoder = server::server::udp::PacketEncoder; using ReassembledCommand = server::server::udp::ReassembledCommand; using StatisticsCategory = stats::ConnectionStatistics::category; public: explicit VoiceClientConnection(server::VoiceClient*); virtual ~VoiceClientConnection(); /* Do not send command packets via send_packet! The send_packet will take ownership of the packet! */ void send_packet(protocol::OutgoingServerPacket* /* packet */); void send_packet(protocol::PacketType /* type */, protocol::PacketFlag::PacketFlags /* flags */, const void* /* payload */, size_t /* payload length */); void send_command(const std::string_view& /* build command command */, bool /* command low */, std::unique_ptr> /* acknowledge listener */); CryptHandler* getCryptHandler(){ return &crypt_handler; } server::VoiceClient* getClient(){ return client; } bool wait_empty_write_and_prepare_queue(std::chrono::time_point until = std::chrono::time_point()); void reset(); void force_insert_command(const pipes::buffer_view& /* payload */); [[nodiscard]] inline auto& packet_statistics() { return this->packet_statistics_; } [[nodiscard]] inline auto& packet_decoder() { return this->packet_decoder_; } [[nodiscard]] inline auto& packet_encoder() { return this->packet_encoder_; } protected: void handle_incoming_datagram(const pipes::buffer_view &buffer); bool verify_encryption(const pipes::buffer_view& /* full packet */); void triggerWrite(); private: server::VoiceClient* client = nullptr; CryptHandler crypt_handler; /* access to CryptHandler is thread save */ server::client::PacketStatistics packet_statistics_{}; PacketDecoder packet_decoder_; PacketEncoder packet_encoder_; spin_mutex pending_commands_lock{}; ReassembledCommand* pending_commands_head{nullptr}; ReassembledCommand** pending_commands_tail{&pending_commands_head}; bool has_command_handling_scheduled{false}; /* locked by pending_commands_lock */ void enqueue_command_execution(ReassembledCommand*); void execute_handle_command_packets(const std::chrono::system_clock::time_point& /* scheduled */); static void callback_packet_decoded(void*, const protocol::ClientPacketParser&); static void callback_command_decoded(void*, ReassembledCommand*&); static void callback_send_acknowledge(void*, uint16_t, bool); static void callback_request_write(void*); static void callback_encode_crypt_error(void*, const PacketEncoder::CryptError&, const std::string&); static void callback_resend_failed(void*, const std::shared_ptr&); static void callback_resend_statistics(void*, size_t); static void callback_outgoing_connection_statistics(void*, StatisticsCategory::value, size_t /* bytes */); }; } }