#pragma once #include #include #include #include #include #include #include #include #include #include #include #include "VoiceClient.h" #include "protocol/AcknowledgeManager.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; public: typedef protocol::PacketRingBuffer> packet_buffer_t; typedef std::array packet_buffers_t; explicit VoiceClientConnection(server::VoiceClient*); virtual ~VoiceClientConnection(); void sendPacket(const std::shared_ptr& original_packet, bool copy = false, bool prepare_directly = false); CryptionHandler* getCryptHandler(){ return &crypt_handler; } server::VoiceClient* getClient(){ return client; } #ifdef VC_USE_READ_QUEUE bool handleNextDatagram(); #endif /* * Split packets waiting in write_process_queue and moves the final buffers to writeQueue. * @returns true when there are more packets to prepare */ bool preprocess_write_packets(); /* return 2 => Nothing | 1 => More and buffer is set | 0 => Buffer is set, nothing more */ int pop_write_buffer(pipes::buffer& /* buffer */); bool wait_empty_write_and_prepare_queue(std::chrono::time_point until = std::chrono::time_point()); protocol::PacketIdManager& getPacketIdManager() { return this->packet_id_manager; } packet_buffers_t& packet_buffers() { return this->_packet_buffers; } void reset(); //buffer::SortedBufferQueue** getReadQueue() { return this->readTypedQueue; } protected: void handleDatagramReceived(const pipes::buffer_view&); bool verify_encryption(const pipes::buffer_view& /* full packet */); void triggerWrite(); private: server::VoiceClient* client = nullptr; //Decryption / encryption stuff CryptionHandler crypt_handler; CompressionHandler compress_handler; AcknowledgeManager acknowledge_handler; //Handle stuff void execute_handle_packet(const std::chrono::system_clock::time_point& /* scheduled */); std::unique_ptr next_reassembled_packet(std::unique_lock& /* packet channel execute lock */, bool& /* have more */); /* ---------- Write declarations ---------- */ spin_lock write_queue_lock; /* queue access isn't for long in general */ std::deque write_queue; struct WritePreprocessCategory { enum value { PING_PONG = 0, //Ping/Pongs ACK = 2, VOICE_WHISPER = 1, //Voice/Whisper COMMAND = 3, INIT = 4, MAX = INIT }; inline static value from_type(protocol::PacketType type) { switch(type) { case protocol::PING: case protocol::PONG: return value::PING_PONG; case protocol::VOICE: case protocol::VOICE_WHISPER: return value::VOICE_WHISPER; case protocol::ACK: case protocol::ACK_LOW: return value::ACK; case protocol::COMMAND: case protocol::COMMAND_LOW: return value::COMMAND; default: return value::INIT; } } }; struct WritePreprocessQueue { int _zero1{0}; bool has_work{false}; std::mutex work_lock{}; spin_lock queue_lock{}; std::deque> queue{}; int _zero{0}; }; std::array write_preprocess_queues{}; /* ---------- Processing ---------- */ /* automatically locked because packets of the same kind should be lock their "work_lock" from their WritePreprocessQueue object */ protocol::PacketIdManager packet_id_manager; /* this function is thread save :) */ std::atomic prepare_process_count{0}; /* current thread count preparing a packet */ bool prepare_packet_for_write(std::vector &/* buffers which need to be transferred */, const std::shared_ptr &/* the packet */, std::unique_lock& /* work lock */); std::recursive_mutex packet_buffer_lock; packet_buffers_t _packet_buffers; uint8_t _packet_buffers_index = 0; }; } }