#pragma once #include #include #include #include #include #include #include "../query/Command.h" namespace ts { namespace protocol { enum PacketType : uint8_t { VOICE = 0x00, VOICE_WHISPER = 0x01, COMMAND = 0x02, COMMAND_LOW = 0x03, PING = 0x04, PONG = 0x05, ACK = 0x06, ACK_LOW = 0x07, INIT1 = 0x08, PACKET_MAX = INIT1, UNDEFINED = 0xFF }; struct PacketTypeProperties { std::string name; PacketType type; int max_length; bool requireAcknowledge; }; class PacketTypeInfo { public: static PacketTypeInfo Voice; static PacketTypeInfo VoiceWhisper; static PacketTypeInfo Command; static PacketTypeInfo CommandLow; static PacketTypeInfo Ping; static PacketTypeInfo Pong; static PacketTypeInfo Ack; static PacketTypeInfo AckLow; static PacketTypeInfo Init1; static PacketTypeInfo Undefined; static PacketTypeInfo fromid(int id); std::string name() const { return data->name; } PacketType type() const { return data->type; } bool requireAcknowledge(){ return data->requireAcknowledge; } bool operator==(const PacketTypeInfo& other) const { return other.data->type == this->data->type; } bool operator!=(const PacketTypeInfo& other){ return other.data->type != this->data->type; } int max_length() const { return data->max_length; } inline bool fragmentable() { return *this == PacketTypeInfo::Command || *this == PacketTypeInfo::CommandLow; } inline bool compressable() { return *this == PacketTypeInfo::Command || *this == PacketTypeInfo::CommandLow; } PacketTypeInfo(const PacketTypeInfo&); PacketTypeInfo(PacketTypeInfo&& remote) : data(remote.data) {} ~PacketTypeInfo(); private: static std::map types; PacketTypeInfo(const std::string&, PacketType, bool, int) noexcept; PacketTypeProperties* data; bool owns_data = false; }; struct PacketIdManagerData { PacketIdManagerData(){ memset(this->packetCounter, 0, sizeof(uint32_t) * 16); } uint32_t packetCounter[16]{}; }; class PacketIdManager { public: PacketIdManager() : data(new PacketIdManagerData){} ~PacketIdManager() = default; PacketIdManager(const PacketIdManager& ref) = default; PacketIdManager(PacketIdManager&& ref) = default; uint16_t nextPacketId(const PacketTypeInfo &type){ return static_cast(data->packetCounter[type.type()]++ & 0xFFFFU); } uint16_t currentPacketId(const PacketTypeInfo &type){ return static_cast(data->packetCounter[type.type()] & 0xFFFFU); } uint16_t generationId(const PacketTypeInfo &type){ return static_cast((data->packetCounter[type.type()] >> 16U) & 0xFFFFU); } void reset() { memset(&data->packetCounter[0], 0, sizeof(uint32_t) * 16); } private: std::shared_ptr data; }; namespace PacketFlag { enum PacketFlag : uint8_t { None = 0x00, Fragmented = 0x10, //If packet type voice then its toggle the CELT Mono NewProtocol = 0x20, Compressed = 0x40, //If packet type voice than its the header Unencrypted = 0x80 }; typedef uint8_t PacketFlags; std::string to_string(PacketFlag flag); } #define MAC_SIZE 8 #define SERVER_HEADER_SIZE 3 #define CLIENT_HEADER_SIZE 5 class BasicPacket { public: explicit BasicPacket(size_t header_length, size_t data_length); virtual ~BasicPacket(); BasicPacket(const BasicPacket&) = delete; BasicPacket(BasicPacket&&) = delete; virtual uint16_t packetId() const = 0; virtual uint16_t generationId() const = 0; virtual PacketTypeInfo type() const = 0; /* packet flag info */ inline bool has_flag(PacketFlag::PacketFlag flag) const { return this->_flags_type_byte() & flag; } inline uint8_t flag_mask() const { return this->_flags_type_byte(); }; [[nodiscard]] std::string flags() const; /* manipulate flags */ inline void set_flags(PacketFlag::PacketFlags flags) { uint8_t& byte = this->_flags_type_byte(); byte &= 0xF; /* clear all flags */ byte |= (flags & 0xF0); } inline void enable_flag(PacketFlag::PacketFlag flag){ this->toggle_flag(flag, true); } inline void toggle_flag(PacketFlag::PacketFlag flag, bool state) { if(state) this->_flags_type_byte() |= flag; else this->_flags_type_byte() &= (uint8_t) ~flag; } virtual void applyPacketId(PacketIdManager &); virtual void applyPacketId(uint16_t, uint16_t); void setListener(std::unique_ptr> listener){ if(!this->type().requireAcknowledge()) throw std::logic_error("Packet type does not support a acknowledge listener!"); this->listener = std::move(listener); } inline std::unique_ptr>& getListener() { return this->listener; } inline size_t length() const { return this->_buffer.length(); } inline const pipes::buffer_view mac() const { return this->_buffer.view(0, MAC_SIZE); } inline pipes::buffer mac() { return this->_buffer.range(0, MAC_SIZE); } inline size_t mac_length() const { return MAC_SIZE; } inline const pipes::buffer_view header() const { return this->_buffer.view(MAC_SIZE, this->_header_length); } inline pipes::buffer header() { return this->_buffer.range(MAC_SIZE, this->_header_length); } inline size_t header_length() const { return this->_header_length; } inline size_t data_length() const { return this->_buffer.length() - (MAC_SIZE + this->_header_length); } inline const pipes::buffer_view data() const { return this->_buffer.view(MAC_SIZE + this->_header_length); } inline pipes::buffer data() { return this->_buffer.range(MAC_SIZE + this->_header_length); } void append_data(const std::vector &data); inline void data(const pipes::buffer_view &data){ this->_buffer.resize(MAC_SIZE + this->_header_length + data.length()); memcpy((char*) this->_buffer.data_ptr() + MAC_SIZE + this->_header_length, data.data_ptr(), data.length()); } inline void mac(const pipes::buffer_view &_new){ assert(_new.length() >= MAC_SIZE); memcpy(this->_buffer.data_ptr(), _new.data_ptr(), MAC_SIZE); } [[nodiscard]] inline bool isEncrypted() const { return this->memory_state.encrypted; } inline void setEncrypted(bool flag){ this->memory_state.encrypted = flag; } [[nodiscard]] inline bool isCompressed() const { return this->memory_state.compressed; } inline void setCompressed(bool flag){ this->memory_state.compressed = flag; } [[nodiscard]] inline bool isFragmentEntry() const { return this->memory_state.fragment_entry; } inline void setFragmentedEntry(bool flag){ this->memory_state.fragment_entry = flag; } Command asCommand(); //Has the size of a byte union { #ifdef WIN32 __pragma(pack(push, 1)) #endif struct { bool encrypted: 1; bool compressed: 1; bool fragment_entry: 1; bool id_branded: 1; } #ifdef WIN32 __pragma(pack(pop)); #else __attribute__((packed)); #endif uint8_t flags = 0; } memory_state; pipes::buffer buffer() { return this->_buffer; } void buffer(pipes::buffer buffer) { assert(buffer.length() >= this->_header_length + MAC_SIZE); this->_buffer = std::move(buffer); } protected: BasicPacket() = default; virtual const uint8_t& _flags_type_byte() const = 0; virtual uint8_t& _flags_type_byte() = 0; virtual void setPacketId(uint16_t, uint16_t) = 0; uint8_t _header_length; pipes::buffer _buffer; uint16_t genId = 0; std::unique_ptr> listener; }; /** * Packet from the client */ class ClientPacket : public BasicPacket { friend std::unique_ptr std::make_unique(); public: static constexpr size_t META_MAC_SIZE = 8; static constexpr size_t META_HEADER_SIZE = CLIENT_HEADER_SIZE; static constexpr size_t META_SIZE = META_MAC_SIZE + META_HEADER_SIZE; [[nodiscard]] static std::unique_ptr from_buffer(const pipes::buffer_view& buffer); ClientPacket(const PacketTypeInfo& type, const pipes::buffer_view& data); ClientPacket(const PacketTypeInfo& type, uint8_t flag_mask, const pipes::buffer_view& data); ~ClientPacket() override; ClientPacket(const ClientPacket&) = delete; ClientPacket(ClientPacket&&) = delete; uint16_t clientId() const; void clientId(uint16_t); uint16_t packetId() const override; uint16_t generationId() const override; void generationId(uint16_t generation) { this->genId = generation; } PacketTypeInfo type() const override; void type(const PacketTypeInfo&); private: ClientPacket() = default; const uint8_t &_flags_type_byte() const override { return this->header().data_ptr()[4]; } uint8_t &_flags_type_byte() override { return this->header().data_ptr()[4]; } void setPacketId(uint16_t, uint16_t) override; }; class PacketParser { public: PacketParser(const PacketParser&) = delete; explicit PacketParser(pipes::buffer_view buffer) : _buffer{std::move(buffer)} {} [[nodiscard]] inline const void* data_ptr() const { return this->_buffer.data_ptr(); } [[nodiscard]] inline void* mutable_data_ptr() { return (void*) this->_buffer.data_ptr(); } [[nodiscard]] inline pipes::buffer_view buffer() const { return this->_buffer; } [[nodiscard]] inline pipes::buffer_view mac() const { return this->_buffer.view(0, 8); } [[nodiscard]] virtual pipes::buffer_view payload() const = 0; [[nodiscard]] virtual size_t payload_length() const = 0; [[nodiscard]] inline uint32_t full_packet_id() const { return this->packet_id() | (this->estimated_generation() << 16U); } [[nodiscard]] virtual uint16_t packet_id() const = 0; [[nodiscard]] virtual uint8_t type() const = 0; [[nodiscard]] virtual uint8_t flags() const = 0; [[nodiscard]] bool is_encrypted() const; [[nodiscard]] bool is_compressed() const; [[nodiscard]] bool is_fragmented() const; [[nodiscard]] uint16_t estimated_generation() const { return this->generation; } void set_estimated_generation(uint16_t gen) { this->generation = gen; } inline void set_decrypted() { this->decrypted = true; } inline void set_uncompressed() { this->uncompressed = true; } inline void set_defragmented() { this->defragmented = true; } protected: uint16_t generation{}; bool decrypted{false}, uncompressed{false}, defragmented{false}; pipes::buffer_view _buffer{}; }; class ClientPacketParser : public PacketParser { public: constexpr static auto kHeaderOffset = 8; constexpr static auto kHeaderLength = CLIENT_HEADER_SIZE; constexpr static auto kPayloadOffset = kHeaderOffset + CLIENT_HEADER_SIZE; explicit ClientPacketParser(pipes::buffer_view buffer) : PacketParser{std::move(buffer)} {} ClientPacketParser(const ClientPacketParser&) = delete; [[nodiscard]] inline bool valid() const { if(this->_buffer.length() < kPayloadOffset) return false; return this->type() <= 8; } [[nodiscard]] inline pipes::buffer_view payload() const override { return this->_buffer.view(kPayloadOffset); } [[nodiscard]] inline size_t payload_length() const override { return this->_buffer.length() - kPayloadOffset; } [[nodiscard]] uint16_t client_id() const; [[nodiscard]] uint16_t packet_id() const override; [[nodiscard]] uint8_t type() const override; [[nodiscard]] uint8_t flags() const override; }; /** * Packet from the server */ class ServerPacket : public BasicPacket { friend std::unique_ptr std::make_unique(); public: static constexpr size_t META_MAC_SIZE = 8; static constexpr size_t META_HEADER_SIZE = SERVER_HEADER_SIZE; static constexpr size_t META_SIZE = META_MAC_SIZE + META_HEADER_SIZE; [[nodiscard]] static std::unique_ptr from_buffer(const pipes::buffer_view& buffer); ServerPacket(uint8_t flagMask, const pipes::buffer_view& data); ServerPacket(const PacketTypeInfo& type, const pipes::buffer_view& data); ServerPacket(PacketTypeInfo type, size_t /* data length */); ~ServerPacket() override; ServerPacket(const ServerPacket&) = delete; ServerPacket(ServerPacket&&) = delete; [[nodiscard]] uint16_t packetId() const override; [[nodiscard]] uint16_t generationId() const override; void generationId(uint16_t generation) { this->genId = generation; } [[nodiscard]] PacketTypeInfo type() const override; private: ServerPacket() = default; [[nodiscard]] const uint8_t &_flags_type_byte() const override { return this->header().data_ptr()[2]; } uint8_t &_flags_type_byte() override { return this->header().data_ptr()[2]; } void setPacketId(uint16_t, uint16_t) override; }; class ServerPacketParser : public PacketParser { public: constexpr static auto kHeaderOffset = 8; constexpr static auto kHeaderLength = SERVER_HEADER_SIZE; constexpr static auto kPayloadOffset = kHeaderOffset + SERVER_HEADER_SIZE; explicit ServerPacketParser(pipes::buffer_view buffer) : PacketParser{std::move(buffer)} {} ServerPacketParser(const ServerPacketParser&) = delete; [[nodiscard]] inline bool valid() const { if(this->_buffer.length() < kPayloadOffset) return false; return this->type() <= 8; } [[nodiscard]] inline pipes::buffer_view payload() const override { return this->_buffer.view(kPayloadOffset); } [[nodiscard]] inline size_t payload_length() const override { return this->_buffer.length() - kPayloadOffset; } [[nodiscard]] uint16_t packet_id() const override; [[nodiscard]] uint8_t type() const override; [[nodiscard]] uint8_t flags() const override; }; } }