#pragma once namespace FSecure::C3::Core { // Forward declarations. struct DeviceBridge; // Typedefs and constants. using ProceduresUnderlyingType = std::int8_t; ///< Underlying type for Procedure number field. using SequenceNumberFieldUnderlyingType = std::uint32_t; /// Underlying type for Query/Response sequence numbers (including type bits = 2 bits). /// Abstract class for all Queries. struct BaseQuery { /// Enumeration for types of responses that can be requested for Queries. enum class ResponseType : std::uint8_t { StatusBits, ///< Bit field: 00 - success, 01 - error, 10 - partial success, 11 - ACK. StatusCode, ///< First - a bit field: 00 - success, 01 - error, 10 - success + extensions, 11 - partial success. Then StatusCode if the first bit-field was equal to 01 or 11. ACK, ///< No status code nor bits. Just send back the ACK packet as soon as possible. StatusCodePlusExtensions, ///< Same as StatusCode, but with extensions after bit-field, if the first bit field was 2 (e.g. iid of a newly added Interface) or after the StatusCode equal to 01 or 11. If status code doesn't require extensions (e.g. "No GDC") then extensions are omitted. None = 255, ///< Do not respond. }; /// Creates Query that is empty and should be filled then sent. /// @param sender informs on the origin of message. BaseQuery(std::weak_ptr sender); /// Creates Query that is empty and should be filled then sent. /// @param responseType informs how recipient should react on message. BaseQuery(ResponseType responseType = ResponseType::None); /// Procedure number getter. /// @return Procedure number. /// @throws std::logic_error if not overriden. virtual ProceduresUnderlyingType GetProcedureNumber() const { throw std::logic_error{ OBF("This method need to be overridden.") }; } /// Deleted copy constructor. BaseQuery(BaseQuery&) = delete; /// Deleted copy assignment operator. BaseQuery& operator=(BaseQuery&) = delete; /// Default move constructor. BaseQuery(BaseQuery&&) = default; /// Default move assignment operator. BaseQuery& operator=(BaseQuery&&) = default; /// Response type setter. /// @param responseType response type to set. void SetResponseType(ResponseType responseType); /// Compiles Query packet into a ByteVector. /// @return Packet buffer. virtual ByteVector ComposeQueryPacket() const = 0; /// Sender Channel Getter. /// @return Sender Channel or nullptr if this Query is yet about to be sent. std::weak_ptr GetSenderChannel(); /// Returns sequence Number. auto GetSequenceNumber() const { return m_SequenceNumber; } protected: /// Constructs Procedure header. /// @return buffer containing composed header. virtual ByteVector CompileProtocolHeader() const = 0; /// Constructs Query packet header out of internal state and data. /// @return Buffer containing the headers. virtual ByteVector CompileQueryHeader() const; private: /// If true then this Query is just a copy of what was sent form remote Relay. If false then this is going to be send after filling up. const bool m_ReceivedOrWillBeSent; /// Underlying type for Query / Response sequence numbers(including type bits = 2 bits). using SequenceNumberFieldUnderlyingType = std::uint32_t; /// Number of bits sequence number occupy in the SequenceNumberType type. static constexpr unsigned s_SequenceNumberBitLength = sizeof(SequenceNumberFieldUnderlyingType) * 8 - 2; /// Sequence number const SequenceNumberFieldUnderlyingType m_SequenceNumber; /// sequence number generator (unique for every Query). /// @return a unique number that can be used for a Query sequence number. static SequenceNumberFieldUnderlyingType GenerateSequenceNumber(); std::uint8_t BuildSequenceNumberField(std::uint8_t statusBits) const; /// Sender of this Query.Equals nullptr if this Query is yet about to be sent. std::weak_ptr m_SenderChannel; /// Type of response requested for this Query. ResponseType m_ResponseType; }; }