#pragma once #include #include #define NO_LOG #ifdef WIN32 #include //Needs to be included; No clue why #endif #include #include #include #include #include #include #include "ServerConnection.h" namespace ts { namespace connection { class CryptionHandler; class CompressionHandler; } } namespace tc { namespace connection { class ServerConnection; namespace connection_state { enum value { INITIALIZING, INIT_LOW, INIT_HIGH, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED }; }; namespace pow_state { enum value : uint8_t { COOKIE_GET, COOKIE_SET, PUZZLE_GET, PUZZLE_SET, PUZZLE_SOLVE, PUZZLE_RESET, COMPLETED, COMMAND_RESET = 127, UNSET = 0xFB }; }; class ProtocolHandler { typedef ts::protocol::PacketRingBuffer packet_buffer_t; typedef std::array packet_buffers_t; friend class ServerConnection; public: ProtocolHandler(ServerConnection*); ~ProtocolHandler(); void reset(); void connect(); void execute_tick(); void execute_resend(); void progress_packet(const pipes::buffer_view& /* buffer */); bool handle_packets(); /* if true we have more left */ void send_packet(const std::shared_ptr& /* packet */); void send_command(const ts::Command& /* command */, const std::function & /* acknowledge callback */ = NULL); void disconnect(const std::string& /* message */); void send_acknowledge(uint16_t /* packet id */, bool /* low */); ecc_key& get_identity_key() { return this->crypto.identity; } inline std::chrono::microseconds current_ping() { return this->ping.value; } connection_state::value connection_state = connection_state::INITIALIZING; server_type::value server_type = server_type::TEASPEAK; private: void do_close_connection(); /* only call from ServerConnection. Close all connections via ServerConnection! */ void handlePacketCommand(const std::shared_ptr&); void handlePacketAck(const std::shared_ptr&); void handlePacketVoice(const std::shared_ptr&); void handlePacketPing(const std::shared_ptr&); void handlePacketInit(const std::shared_ptr&); bool create_datagram_packets(std::vector &result, const std::shared_ptr &packet); ServerConnection* handle; std::chrono::system_clock::time_point connect_timestamp; std::chrono::system_clock::time_point disconnect_timestamp; uint8_t disconnect_id = 0; struct { pow_state::value state; uint64_t client_ts3_build_timestamp = 173265950 /* TS3 */; /* needs to be lower than 173265950 for old stuff, else new protocol */ uint8_t client_control_data[4] = {0,0,0,0}; uint8_t server_control_data[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; uint8_t server_data[100]; std::chrono::system_clock::time_point last_response; std::chrono::system_clock::time_point last_resend; pipes::buffer last_buffer; } pow; void pow_send_cookie_get(); struct { uint8_t alpha[10]; uint8_t beta[54]; uint8_t beta_length; /* 10 or 54 */ ecc_key identity{}; std::string initiv_command; } crypto; std::string generate_client_initiv(); uint16_t client_id = 0; ts::protocol::PacketIdManager _packet_id_manager; packet_buffers_t _packet_buffers; std::array _packet_buffer_overflow{false}; std::array incoming_generation_estimators{}; /* implementation is thread save */ uint8_t _packet_buffers_index = 0; bool crypt_setupped{false}; ts::connection::CryptHandler crypt_handler; ts::connection::CompressionHandler compression_handler; ts::connection::AcknowledgeManager acknowledge_handler; void handleCommandInitIVExpend(ts::Command&); void handleCommandInitIVExpend2(ts::Command&); void handleCommandInitServer(ts::Command&); struct { std::chrono::system_clock::time_point ping_send_timestamp; std::chrono::system_clock::time_point ping_received_timestamp; std::chrono::microseconds value; uint16_t ping_id; std::chrono::microseconds interval = std::chrono::microseconds(2500); } ping; void ping_send_request(); }; } }