diff --git a/include/sp/protocol/GenericHandler.h b/include/sp/common/GenericHandler.h similarity index 100% rename from include/sp/protocol/GenericHandler.h rename to include/sp/common/GenericHandler.h diff --git a/include/sp/common/Reflection.h b/include/sp/common/Reflection.h deleted file mode 100644 index d0fcc4c..0000000 --- a/include/sp/common/Reflection.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include -#include - -namespace sp { - -template -std::string GetBasicClassName(const T& a_Value) { - int status; - char* demangled = abi::__cxa_demangle(typeid(a_Value).name(), 0, 0, &status); - if (status != 0) - return ""; - return std::string(demangled); -} - -template -std::string GetBasicClassName() { - int status; - char* demangled = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status); - if (status != 0) - return ""; - return std::string(demangled); -} - -template -struct Reflector { - static std::string GetClassName() { - return GetBasicClassName(); - } -}; - -template <> -struct Reflector { - static std::string GetClassName() { - return "std::string"; - } -}; - -template -struct Reflector> { - static std::string GetClassName(); -}; - -template -struct Reflector> { - static std::string GetClassName(); -}; - -template -std::string Reflector>::GetClassName() { - return "std::vector<" + Reflector::GetClassName() + ">"; -} - -template -std::string Reflector>::GetClassName() { - return "std::map<" + Reflector::GetClassName() + ", " + Reflector::GetClassName() + ">"; -} - -} // namespace sp diff --git a/include/sp/common/VarInt.h b/include/sp/common/VarInt.h index 2f0bf6b..7608dfb 100644 --- a/include/sp/common/VarInt.h +++ b/include/sp/common/VarInt.h @@ -7,12 +7,14 @@ #include #include -#include +#include namespace sp { class DataBuffer; +using ReadFunc = std::function; + /** * \class VarInt * \brief Variable-length format such that smaller numbers use fewer bytes. @@ -57,6 +59,7 @@ class VarInt { */ friend DataBuffer& operator>>(DataBuffer& in, VarInt& var); + void Read(const ReadFunc& read); }; } // namespace sp diff --git a/include/sp/io/File.h b/include/sp/io/File.h deleted file mode 100644 index 2b329e6..0000000 --- a/include/sp/io/File.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include -#include - -namespace sp { -namespace io { - -struct FileTag { - enum OpenMode { - In = 1, - Out = 1 << 1, - }; -}; - -template <> -class IOInterface { - private: - std::unique_ptr m_FileInput; - std::unique_ptr m_FileOutput; - - public: - IOInterface(const std::string& a_FilePath, unsigned int a_OpenMode); - IOInterface(IOInterface&& other); - - DataBuffer Read(std::size_t a_Amount); - void Write(const sp::DataBuffer& a_Data); -}; - -using File = IOInterface; - -} // namespace io -} // namespace sp diff --git a/include/sp/io/IOInterface.h b/include/sp/io/IOInterface.h deleted file mode 100644 index aca8cbd..0000000 --- a/include/sp/io/IOInterface.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include -#include - -namespace sp { -namespace io { - -template -class IOInterface { - public: - DataBuffer Read(std::size_t a_Amount); - void Write(const DataBuffer& a_Data); -}; - -template -class MessageEncapsulator { - public: - static DataBuffer Encapsulate(const DataBuffer& a_Data, const TOption& a_Option); - static DataBuffer Decapsulate(DataBuffer& a_Data, const TOption& a_Option); -}; - -template -class Stream { - protected: - MessageDispatcher m_Dispatcher; - IOInterface m_Interface; - std::tuple m_Options; - - using MessageBase = typename MessageDispatcher::MessageBaseType; - - public: - Stream() {} - Stream(IOInterface&& a_Interface, TOptions&&... a_Options); - Stream(Stream&& a_Stream); - - void RecieveMessages(); - void SendMessage(const MessageBase& a_Message); - - - template - TOption& GetOption() { - return std::get(m_Options); - } - - MessageDispatcher& GetDispatcher() { - return m_Dispatcher; - } - - private: - static DataBuffer Encapsulate(const DataBuffer& a_Data, const TOptions&... a_Options); - static DataBuffer Decapsulate(DataBuffer& a_Data, const TOptions&... a_Options); -}; - -} // namespace io -} // namespace sp - -#include \ No newline at end of file diff --git a/include/sp/io/IOInterfaceImpl.inl b/include/sp/io/IOInterfaceImpl.inl deleted file mode 100644 index 12e153b..0000000 --- a/include/sp/io/IOInterfaceImpl.inl +++ /dev/null @@ -1,129 +0,0 @@ -#pragma once - -#include -#include - -namespace sp { - -namespace details { - -template -struct MessageEncapsulatorPack {}; - -template <> -struct MessageEncapsulatorPack<> { - static DataBuffer Encapsulate(const DataBuffer& a_Data) { - return a_Data; - } - static DataBuffer Decapsulate(DataBuffer& a_Data) { - return a_Data; - } -}; - -template -struct MessageEncapsulatorPack { - static DataBuffer Encapsulate(const DataBuffer& a_Data, const TOption& a_Option, const TOptions&... a_Options) { - DataBuffer data = io::MessageEncapsulator::Encapsulate(a_Data, a_Option); - return MessageEncapsulatorPack::Encapsulate(data, a_Options...); - } - static DataBuffer Decapsulate(DataBuffer& a_Data, const TOption& a_Option, const TOptions&... a_Options) { - DataBuffer data = io::MessageEncapsulator::Decapsulate(a_Data, a_Option); - return MessageEncapsulatorPack::Decapsulate(data, a_Options...); - } -}; - -} // namespace details - -namespace io { - -template -Stream::Stream(IOInterface&& a_Interface, TOptions&&... a_Options) : - m_Interface(std::move(a_Interface)), m_Options(std::make_tuple(std::move(a_Options)...)) {} - -template -Stream::Stream( - Stream&& a_Stream) : - m_Dispatcher(std::move(a_Stream.m_Dispatcher)), m_Interface(std::move(a_Stream.m_Interface)) {} - -template -void Stream::SendMessage(const MessageBase& a_Message) { - DataBuffer data = a_Message.Write(); - TupleForEach([&data](const auto&... a_Options) { - data = Encapsulate(data, a_Options...); - }, m_Options); - DataBuffer finalData; - finalData.Reserve(data.GetSize() + sizeof(VarInt::MAX_VALUE)); - finalData << VarInt{data.GetSize()} << data; - m_Interface.Write(finalData); -} - -template -void Stream::RecieveMessages() { - while (true) { - // reading the first VarInt part byte by byte - std::uint64_t lenghtValue = 0; - unsigned int readPos = 0; - - while (true) { - static constexpr int SEGMENT_BITS = (1 << 7) - 1; - static constexpr int CONTINUE_BIT = 1 << 7; - - DataBuffer buffer = m_Interface.Read(sizeof(std::uint8_t)); - - // eof - if (buffer.GetSize() == 0) - return; - - std::uint8_t part; - buffer >> part; - lenghtValue |= static_cast(part & SEGMENT_BITS) << readPos; - - if ((part & CONTINUE_BIT) == 0) - break; - - readPos += 7; - - if (readPos >= 8 * sizeof(lenghtValue)) - throw std::runtime_error("VarInt is too big"); - } - - // nothing to read - if (lenghtValue == 0) - return; - - DataBuffer buffer; - buffer = m_Interface.Read(lenghtValue); - - TupleForEach([&buffer, lenghtValue](const auto&... a_Options) { - buffer = Decapsulate(buffer, a_Options...); - }, m_Options); - - VarInt packetType; - buffer >> packetType; - - static const MessageFactory messageFactory; - - std::unique_ptr message = messageFactory.CreateMessage(packetType.GetValue()); - - assert(message != nullptr); - - message->Read(buffer); - - GetDispatcher().Dispatch(*message); - } -} - -template -DataBuffer Stream::Encapsulate( - const DataBuffer& a_Data, const TOptions&... a_Options) { - return details::MessageEncapsulatorPack::Encapsulate(a_Data, a_Options...); -} - -template -DataBuffer Stream::Decapsulate( - DataBuffer& a_Data, const TOptions&... a_Options) { - return details::MessageEncapsulatorPack::Decapsulate(a_Data, a_Options...); -} - -} // namespace io -} // namespace sp \ No newline at end of file diff --git a/include/sp/io/IoInterface.h b/include/sp/io/IoInterface.h new file mode 100644 index 0000000..037dfef --- /dev/null +++ b/include/sp/io/IoInterface.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace sp { + +class IoInterface { + public: + virtual DataBuffer Read(std::size_t a_Amount) = 0; + virtual void Write(const DataBuffer& a_Data) = 0; +}; + +} // namespace sp diff --git a/include/sp/io/Memory.h b/include/sp/io/Memory.h deleted file mode 100644 index 83021bc..0000000 --- a/include/sp/io/Memory.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include - -namespace sp { -namespace io { - -struct MemoryTag {}; - -template <> -class IOInterface { - private: - sp::DataBuffer m_VirtualIO; - - public: - sp::DataBuffer Read(std::size_t a_Amount); - void Write(const sp::DataBuffer& a_Data); -}; - -using Memory = IOInterface; - -} // namespace io -} // namespace sp diff --git a/include/sp/io/MessageEncapsulator.h b/include/sp/io/MessageEncapsulator.h new file mode 100644 index 0000000..d8796fd --- /dev/null +++ b/include/sp/io/MessageEncapsulator.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace sp { + +class MessageEncapsulator { + public: + MessageEncapsulator() {} + virtual ~MessageEncapsulator() {} + + virtual DataBuffer Encapsulate(const DataBuffer& a_Data) = 0; + virtual DataBuffer Decapsulate(DataBuffer& a_Data) = 0; +}; + +} // namespace sp diff --git a/include/sp/io/MessageIO.h b/include/sp/io/MessageIO.h new file mode 100644 index 0000000..9dc5440 --- /dev/null +++ b/include/sp/io/MessageIO.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include + +namespace sp { +namespace details { + +template +void WriteField(DataBuffer& a_Buffer, const T& a_Data) { + T swapped = a_Data; + ToNetwork(swapped); + a_Buffer << swapped; +} + +template +void ReadField(DataBuffer& a_Buffer, T& a_Data) { + a_Buffer >> a_Data; + FromNetwork(a_Data); +} + +template +DataBuffer WriteMessage(const TData& a_MessageData) { + DataBuffer buffer; + boost::pfr::for_each_field(a_MessageData, [&buffer](const auto& a_Field) { WriteField(buffer, a_Field); }); + return buffer; +} + +template +void ReadMessage(DataBuffer& a_Buffer, TData& a_MessageData) { + boost::pfr::for_each_field(a_MessageData, [&a_Buffer](auto& a_Field) { ReadField(a_Buffer, a_Field); }); +} + +} // namespace details +} // namespace sp diff --git a/include/sp/io/MessageStream.h b/include/sp/io/MessageStream.h new file mode 100644 index 0000000..c5442f8 --- /dev/null +++ b/include/sp/io/MessageStream.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include +#include + +namespace sp { + +template +class MessageStream { + private: + std::vector m_Encapsulators; + std::shared_ptr m_Stream; + + using MessageBaseType = typename TMessageFactory::MessageBaseType; + using MessageIdType = typename MessageBaseType::MessageIdType; + + public: + MessageStream(std::shared_ptr&& a_Stream) : m_Stream(std::move(a_Stream)) {} + + std::unique_ptr ReadMessage(); + std::unique_ptr ReadMessage(MessageIdType a_Id); + + void WriteMessage(const MessageBaseType& a_Message, bool a_WriteId = true); + + private: + DataBuffer ReadAndDecapsulate(); + std::unique_ptr MakeMessage(DataBuffer& buffer, MessageIdType a_Id); +}; + +} // namespace sp + +#include \ No newline at end of file diff --git a/include/sp/io/MessageStream.inl b/include/sp/io/MessageStream.inl new file mode 100644 index 0000000..98231f9 --- /dev/null +++ b/include/sp/io/MessageStream.inl @@ -0,0 +1,63 @@ +#pragma once + +#include +#include + +namespace sp { + +template +DataBuffer MessageStream::ReadAndDecapsulate() { + VarInt messageLength; + messageLength.Read([this](std::uint8_t& data) { m_Stream->Read(1) >> data; }); + std::size_t amount = messageLength.GetValue(); + DataBuffer buffer = m_Stream->Read(amount); + + for (MessageEncapsulator& enc : m_Encapsulators) { + buffer = enc.Decapsulate(buffer); + } + + return buffer; +} + +template +std::unique_ptr MessageStream::MakeMessage(DataBuffer& buffer, MessageIdType a_Id) { + static const TMessageFactory FACTORY; + auto message = FACTORY.CreateMessage(a_Id); + message->Read(buffer); + return message; +} + +template +std::unique_ptr MessageStream::ReadMessage(MessageIdType a_Id) { + + DataBuffer buffer = ReadAndDecapsulate(); + + return MakeMessage(buffer, a_Id); +} + +template +std::unique_ptr MessageStream::ReadMessage() { + DataBuffer buffer = ReadAndDecapsulate(); + + VarInt messageId; + buffer >> messageId; + + return MakeMessage(buffer, MessageIdType(messageId.GetValue())); +} + +template +void MessageStream::WriteMessage(const MessageBaseType& a_Message, bool a_WriteId) { + DataBuffer buffer; + if (a_WriteId) + buffer << VarInt{static_cast(a_Message.GetId())}; + buffer << a_Message.Write(); + for (MessageEncapsulator& enc : m_Encapsulators) { + buffer = enc.Encapsulate(buffer); + } + DataBuffer header; + header << VarInt{buffer.GetSize()}; + m_Stream->Write(header); + m_Stream->Write(buffer); +} + +} // namespace sp diff --git a/include/sp/io/StdIo.h b/include/sp/io/StdIo.h new file mode 100644 index 0000000..50de28e --- /dev/null +++ b/include/sp/io/StdIo.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +namespace sp { + +class StdInput : public IoInterface { + private: + std::istream& m_Io; + + public: + StdInput(std::istream& a_Io) : m_Io(a_Io) {} + + virtual DataBuffer Read(std::size_t a_Amount) override { + DataBuffer buffer(a_Amount); + m_Io.read(reinterpret_cast(buffer.data()), a_Amount); + return buffer; + } + + virtual void Write(const DataBuffer& a_Data) override {} +}; + +class StdOuput : public IoInterface { + private: + std::ostream& m_Io; + + public: + StdOuput(std::ostream& a_Io) : m_Io(a_Io) {} + + virtual DataBuffer Read(std::size_t a_Amount) override { + return {}; + } + + virtual void Write(const DataBuffer& a_Data) override { + m_Io.write(reinterpret_cast(a_Data.data()), a_Data.GetSize()); + } +}; + +} // namespace sp diff --git a/include/sp/protocol/ConcreteMessage.h b/include/sp/protocol/ConcreteMessage.h index 2a0da69..f1a4960 100644 --- a/include/sp/protocol/ConcreteMessage.h +++ b/include/sp/protocol/ConcreteMessage.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include namespace sp { @@ -9,7 +9,6 @@ template class ConcreteMessage : public MessageBase { public: using DataType = TData; - using ThisType = ConcreteMessage; template ConcreteMessage(const T&... args) : m_Data{args...} {} @@ -21,15 +20,15 @@ class ConcreteMessage : public MessageBase { } virtual void Dispatch(THandler& handler) const override { - handler.Handle(static_cast(*this)); + handler.Handle(static_cast(m_Data)); } - virtual void Read(std::istream& a_Is) override { - details::ReadMessage(a_Is, m_Data); + virtual void Read(DataBuffer& a_Buffer) override { + details::ReadMessage(a_Buffer, m_Data); } - virtual void Write(std::ostream& a_Os) const override { - details::WriteMessage(a_Os, m_Data); + virtual DataBuffer Write() const override { + return details::WriteMessage(m_Data); } private: diff --git a/include/sp/protocol/MessageBase.h b/include/sp/protocol/MessageBase.h index ba3e10b..4db490b 100644 --- a/include/sp/protocol/MessageBase.h +++ b/include/sp/protocol/MessageBase.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace sp { @@ -17,8 +18,8 @@ class MessageBase { virtual void Dispatch(HandlerType& handler) const = 0; - virtual void Read(std::istream& a_Is) = 0; - virtual void Write(std::ostream& a_Os) const = 0; + virtual void Read(DataBuffer& a_Buffer) = 0; + virtual DataBuffer Write() const = 0; }; } // namespace sp diff --git a/include/sp/protocol/MessageFactory.h b/include/sp/protocol/MessageFactory.h index c7c5d59..0957977 100644 --- a/include/sp/protocol/MessageFactory.h +++ b/include/sp/protocol/MessageFactory.h @@ -12,6 +12,7 @@ template class MessageFactory { public: using IdType = typename TBase::MessageIdType; + using MessageBaseType = TBase; MessageFactory() { constexpr std::size_t messageCount = std::tuple_size_v; diff --git a/include/sp/protocol/MessageHandler.h b/include/sp/protocol/MessageHandler.h new file mode 100644 index 0000000..b8d4ee7 --- /dev/null +++ b/include/sp/protocol/MessageHandler.h @@ -0,0 +1,133 @@ +#pragma once + +#include + +namespace sp +{ + // This class is inspired by https://arobenko.gitbooks.io/comms-protocols-cpp/content/ + + // TAll is all the message types, that need to be handled, bundled in std::tuple + template + class MessageHandler; + + // Big boy to process packets 20 by 20, preventing needlessly copying vtable many times at each inheritance stage + template + class MessageHandler > : public MessageHandler > + { + using Base = MessageHandler >; + public: + using Base::Handle; // Don't hide all Handle() functions from base classes + virtual void Handle(const typename T1::DataType& msg) {} + virtual void Handle(const typename T2::DataType& msg) {} + virtual void Handle(const typename T3::DataType& msg) {} + virtual void Handle(const typename T4::DataType& msg) {} + virtual void Handle(const typename T5::DataType& msg) {} + virtual void Handle(const typename T6::DataType& msg) {} + virtual void Handle(const typename T7::DataType& msg) {} + virtual void Handle(const typename T8::DataType& msg) {} + virtual void Handle(const typename T9::DataType& msg) {} + virtual void Handle(const typename T10::DataType& msg) {} + virtual void Handle(const typename T11::DataType& msg) {} + virtual void Handle(const typename T12::DataType& msg) {} + virtual void Handle(const typename T13::DataType& msg) {} + virtual void Handle(const typename T14::DataType& msg) {} + virtual void Handle(const typename T15::DataType& msg) {} + virtual void Handle(const typename T16::DataType& msg) {} + virtual void Handle(const typename T17::DataType& msg) {} + virtual void Handle(const typename T18::DataType& msg) {} + virtual void Handle(const typename T19::DataType& msg) {} + virtual void Handle(const typename T20::DataType& msg) {} + }; + + // 10 by 10 + template + class MessageHandler > : public MessageHandler > + { + using Base = MessageHandler >; + public: + using Base::Handle; // Don't hide all Handle() functions from base classes + virtual void Handle(const typename T1::DataType& msg) {} + virtual void Handle(const typename T2::DataType& msg) {} + virtual void Handle(const typename T3::DataType& msg) {} + virtual void Handle(const typename T4::DataType& msg) {} + virtual void Handle(const typename T5::DataType& msg) {} + virtual void Handle(const typename T6::DataType& msg) {} + virtual void Handle(const typename T7::DataType& msg) {} + virtual void Handle(const typename T8::DataType& msg) {} + virtual void Handle(const typename T9::DataType& msg) {} + virtual void Handle(const typename T10::DataType& msg) {} + }; + + // 5 by 5 + template < + typename T1, typename T2, typename T3, typename T4, typename T5, + typename... TRest> + class MessageHandler > : public MessageHandler > + { + using Base = MessageHandler >; + public: + using Base::Handle; // Don't hide all Handle() functions from base classes + virtual void Handle(const typename T1::DataType& msg) {} + virtual void Handle(const typename T2::DataType& msg) {} + virtual void Handle(const typename T3::DataType& msg) {} + virtual void Handle(const typename T4::DataType& msg) {} + virtual void Handle(const typename T5::DataType& msg) {} + }; + + // Deal with rest with 4 types + template + class MessageHandler > + { + public: + virtual ~MessageHandler() {} + virtual void Handle(const typename T1::DataType& msg) {} + virtual void Handle(const typename T2::DataType& msg) {} + virtual void Handle(const typename T3::DataType& msg) {} + virtual void Handle(const typename T4::DataType& msg) {} + }; + + // Deal with rest with 3 types + template < typename T1, typename T2, typename T3> + class MessageHandler > + { + public: + virtual ~MessageHandler() {} + virtual void Handle(const typename T1::DataType& msg) {} + virtual void Handle(const typename T2::DataType& msg) {} + virtual void Handle(const typename T3::DataType& msg) {} + }; + + // Deal with rest with 2 types + template + class MessageHandler > + { + public: + virtual ~MessageHandler() {} + virtual void Handle(const typename T1::DataType& msg) {} + virtual void Handle(const typename T2::DataType& msg) {} + }; + + // Deal with rest with 1 type + template + class MessageHandler > + { + public: + virtual ~MessageHandler() {} + virtual void Handle(const typename T1::DataType& msg) {} + }; + + // Deal with rest with 0 type + template <> + class MessageHandler > + { + public: + virtual ~MessageHandler() {} + }; + +} // sp \ No newline at end of file diff --git a/include/sp/protocol/MessageIO.h b/include/sp/protocol/MessageIO.h deleted file mode 100644 index d3661f5..0000000 --- a/include/sp/protocol/MessageIO.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace sp { -namespace details { - -template -void WriteField(std::ostream& a_Os, const T& a_Data) { - T swapped = a_Data; - ToNetwork(swapped); - a_Os.write(reinterpret_cast(&swapped), sizeof(a_Data)); -} - -template -void ReadField(std::istream& a_Is, T& a_Data) { - a_Is.read(reinterpret_cast(&a_Data), sizeof(a_Data)); - FromNetwork(a_Data); -} - -template -void WriteMessage(std::ostream& a_Os, const TData& a_MessageData) { - boost::pfr::for_each_field(a_MessageData, [&a_Os](const auto& a_Field) { - WriteField(a_Os, a_Field); - }); -} - -template -void ReadMessage(std::istream& a_Is, TData& a_MessageData) { - boost::pfr::for_each_field(a_MessageData, [&a_Is](auto& a_Field) { - ReadField(a_Is, a_Field); - }); -} - -} // namespace details -} // namespace sp diff --git a/src/sp/common/VarInt.cpp b/src/sp/common/VarInt.cpp index a02bf6f..30e2463 100644 --- a/src/sp/common/VarInt.cpp +++ b/src/sp/common/VarInt.cpp @@ -29,24 +29,29 @@ DataBuffer& operator<<(DataBuffer& out, const VarInt& var) { } DataBuffer& operator>>(DataBuffer& in, VarInt& var) { - var.m_Value = 0; + var.Read([&in](std::uint8_t& data){ + in.ReadSome(&data, 1); + }); + return in; +} + +void VarInt::Read(const ReadFunc& read) { + m_Value = 0; unsigned int position = 0; std::uint8_t currentByte; while (true) { - in.ReadSome(¤tByte, 1); - var.m_Value |= static_cast(currentByte & SEGMENT_BITS) << position; + read(currentByte); + m_Value |= static_cast(currentByte & SEGMENT_BITS) << position; if ((currentByte & CONTINUE_BIT) == 0) break; position += 7; - if (position >= 8 * sizeof(var.m_Value)) + if (position >= 8 * sizeof(m_Value)) throw std::runtime_error("VarInt is too big"); } - - return in; } } // namespace sp diff --git a/src/sp/extensions/Compress.cpp b/src/sp/extensions/Compress.cpp index fbb67ac..e69de29 100644 --- a/src/sp/extensions/Compress.cpp +++ b/src/sp/extensions/Compress.cpp @@ -1,89 +0,0 @@ -#include - -#include -#include -#include - -namespace sp { -namespace zlib { - -static DataBuffer Inflate(const std::uint8_t* source, std::size_t size, std::size_t uncompressedSize) { - DataBuffer result; - result.Resize(uncompressedSize); - - uncompress(static_cast(result.data()), reinterpret_cast(&uncompressedSize), static_cast(source), - static_cast(size)); - - assert(result.GetSize() == uncompressedSize); - return result; -} - -static DataBuffer Deflate(const std::uint8_t* source, std::size_t size) { - DataBuffer result; - uLongf compressedSize = size; - - result.Resize(size); // Resize for the compressed data to fit into - compress(static_cast(result.data()), &compressedSize, static_cast(source), static_cast(size)); - result.Resize(compressedSize); // Resize to cut useless data - - return result; -} - -DataBuffer Compress(const DataBuffer& buffer, std::size_t a_CompressionThreshold) { - DataBuffer packet; - - if (buffer.GetSize() < a_CompressionThreshold) { - // Don't compress since it's a small packet - packet << VarInt{0}; - packet << buffer; - return packet; - } - - DataBuffer compressedData = Deflate(buffer.data(), buffer.GetSize()); - VarInt uncompressedDataLength = buffer.GetSize(); - - if (compressedData.GetSize() >= buffer.GetSize()) { - // the compression is overkill so we don't send the compressed buffer - packet << VarInt{0}; - packet << buffer; - } else { - packet << uncompressedDataLength; - packet << compressedData; - } - - return packet; -} - -DataBuffer Decompress(DataBuffer& buffer, std::uint64_t packetLength) { - VarInt uncompressedLength; - buffer >> uncompressedLength; - - std::uint64_t compressedLength = packetLength - uncompressedLength.GetSerializedLength(); - - if (uncompressedLength.GetValue() == 0) { - // Data already uncompressed. Nothing to do - DataBuffer ret; - buffer.ReadSome(ret, compressedLength); - return ret; - } - - assert(buffer.GetReadOffset() + compressedLength <= buffer.GetSize()); - - return Inflate(buffer.data() + buffer.GetReadOffset(), compressedLength, uncompressedLength.GetValue()); -} - -} // namespace zlib - -namespace io { - -DataBuffer MessageEncapsulator::Encapsulate(const DataBuffer& a_Data, const option::ZlibCompress& a_Option) { - static constexpr std::size_t MAX_COMPRESS_THRESHOLD = VarInt::MAX_VALUE; - return zlib::Compress(a_Data, a_Option.m_Enabled ? a_Option.m_CompressionThreshold : MAX_COMPRESS_THRESHOLD); -} - -DataBuffer MessageEncapsulator::Decapsulate(DataBuffer& a_Data, const option::ZlibCompress& a_Option) { - return zlib::Decompress(a_Data, a_Data.GetSize()); -} - -} // namespace io -} // namespace sp diff --git a/src/sp/extensions/TcpListener.cpp b/src/sp/extensions/TcpListener.cpp index 330c975..e69de29 100644 --- a/src/sp/extensions/TcpListener.cpp +++ b/src/sp/extensions/TcpListener.cpp @@ -1,114 +0,0 @@ -#include - - -#ifdef _WIN32 - -// Windows - -#include -#include - -#define ioctl ioctlsocket -#define WOULDBLOCK WSAEWOULDBLOCK -#define MSG_DONTWAIT 0 - -#else - -// Linux/Unix - -#include -#include -#include -#include -#include -#include -#include - -#define closesocket close -#define WOULDBLOCK EWOULDBLOCK -#define SD_BOTH SHUT_RDWR - -#endif - - - -#ifndef INVALID_SOCKET -#define INVALID_SOCKET -1 -#endif - - -namespace sp { -namespace io { - -TcpListener::TcpListener(std::uint16_t a_Port, int a_MaxConnexions) { - if ((m_Handle = static_cast(socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))) < 0) { - throw SocketError("Failed to create server socket"); - } - - struct sockaddr_in address; - address.sin_family = AF_INET; - address.sin_addr.s_addr = INADDR_ANY; - address.sin_port = htons(a_Port); - - if (bind(m_Handle, reinterpret_cast(&address), sizeof(address)) < 0) - throw SocketError("Failed to create server socket"); - - if (listen(m_Handle, a_MaxConnexions) < 0) - throw SocketError("Failed to create server socket"); - - socklen_t len = sizeof(address); - if (getsockname(m_Handle, reinterpret_cast(&address), &len) < 0) - throw SocketError("Failed to create server socket"); - - m_Port = ntohs(address.sin_port); - m_MaxConnections = a_MaxConnexions; -} - - -TcpListener::~TcpListener() { - Close(); -} - -std::unique_ptr TcpListener::Accept() { - sockaddr remoteAddress; - int addrlen = sizeof(remoteAddress); - - auto newSocket = std::make_unique(); - - newSocket->m_Handle = static_cast( - accept(m_Handle, reinterpret_cast(&remoteAddress), reinterpret_cast(&addrlen))); - - if (newSocket->m_Handle < 0) - return nullptr; - - newSocket->m_Status = TcpSocket::Status::Connected; - return newSocket; -} - -void TcpListener::Close() { - if (m_Handle > 0) { - closesocket(m_Handle); - shutdown(m_Handle, SD_BOTH); - } -} - -bool TcpListener::SetBlocking(bool a_Blocking) { - unsigned long mode = !a_Blocking; - - if (ioctl(m_Handle, FIONBIO, &mode) < 0) { - return false; - } - - return true; -} - -std::uint16_t TcpListener::GetListeningPort() const { - return m_Port; -} - -int TcpListener::GetMaximumConnections() const { - return m_MaxConnections; -} - -} // namespace io -} // namespace sp diff --git a/src/sp/extensions/TcpSocket.cpp b/src/sp/extensions/TcpSocket.cpp index ab08b3a..e69de29 100644 --- a/src/sp/extensions/TcpSocket.cpp +++ b/src/sp/extensions/TcpSocket.cpp @@ -1,164 +0,0 @@ -#include - -#ifdef _WIN32 - -// Windows - -#include -#include - -#define ioctl ioctlsocket -#define WOULDBLOCK WSAEWOULDBLOCK -#define MSG_DONTWAIT 0 - -#else - -// Linux/Unix - -#include -#include -#include -#include -#include -#include -#include - -#define closesocket close -#define WOULDBLOCK EWOULDBLOCK - -#endif - - - -#ifndef INVALID_SOCKET -#define INVALID_SOCKET -1 -#endif - - -namespace sp { -namespace io { - -TcpSocket::IOInterface() : m_Handle(static_cast(INVALID_SOCKET)), m_Status(Status::Disconnected) {} - -TcpSocket::IOInterface(const std::string& a_Host, std::uint16_t a_Port) : IOInterface() { - Connect(a_Host, a_Port); -} - -TcpSocket::IOInterface(IOInterface&& a_Other) { - std::swap(m_Handle, a_Other.m_Handle); - std::swap(m_Status, a_Other.m_Status); -} - -TcpSocket::~IOInterface() {} - -void TcpSocket::Connect(const std::string& a_Host, std::uint16_t a_Port) { - struct addrinfo hints {}; - - struct addrinfo* result = nullptr; - - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - m_Status = Status::Error; - - if (getaddrinfo(a_Host.c_str(), std::to_string(static_cast(a_Port)).c_str(), &hints, &result) != 0) { - throw SocketError("Failed to get address info"); - } - - m_Handle = static_cast(socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)); - if (m_Handle < 0) { - throw SocketError("Failed to create socket"); - } - - struct addrinfo* ptr = nullptr; - for (ptr = result; ptr != nullptr; ptr = ptr->ai_next) { - struct sockaddr* sockaddr = ptr->ai_addr; - if (connect(m_Handle, sockaddr, sizeof(sockaddr_in)) == 0) { - break; - } - } - - freeaddrinfo(result); - - if (!ptr) { - throw SocketError("Could not find a suitable interface for connecting"); - } - - m_Status = Status::Connected; -} - -DataBuffer TcpSocket::Read(std::size_t a_Amount) { - DataBuffer buffer(a_Amount); - - std::size_t totalRecieved = 0; - - while (totalRecieved < a_Amount) { - int recvAmount = - recv(m_Handle, reinterpret_cast(buffer.data() + totalRecieved), static_cast(a_Amount - totalRecieved), 0); - if (recvAmount <= 0) { -#if defined(_WIN32) || defined(WIN32) - int err = WSAGetLastError(); -#else - int err = errno; -#endif - if (err == WOULDBLOCK) { - // we are in non blocking mode and nothing is available - return {}; - } - - Disconnect(); - m_Status = Status::Error; - throw SocketError("Error while reading"); - } - totalRecieved += recvAmount; - } - return buffer; -} - -void TcpSocket::Write(const sp::DataBuffer& a_Data) { - if (GetStatus() != Status::Connected) - return; - - std::size_t sent = 0; - - while (sent < a_Data.GetSize()) { - int cur = send(m_Handle, reinterpret_cast(a_Data.data() + sent), static_cast(a_Data.GetSize() - sent), 0); - - if (cur <= 0) { - Disconnect(); - m_Status = Status::Error; - return; - } - sent += static_cast(cur); - } -} - -bool TcpSocket::SetBlocking(bool a_Block) { - unsigned long mode = !a_Block; - - if (ioctl(m_Handle, FIONBIO, &mode) < 0) { - return false; - } - - return true; -} - -TcpSocket::Status TcpSocket::GetStatus() const { - return m_Status; -} - -void TcpSocket::Disconnect() { - if (m_Handle > 0) - closesocket(m_Handle); - m_Status = Status::Disconnected; -} - -TcpSocket& TcpSocket::operator=(IOInterface&& a_Other) { - std::swap(m_Handle, a_Other.m_Handle); - std::swap(m_Status, a_Other.m_Status); - return *this; -} - -} // namespace io -} // namespace sp diff --git a/src/sp/io/File.cpp b/src/sp/io/File.cpp index 300c0aa..e69de29 100644 --- a/src/sp/io/File.cpp +++ b/src/sp/io/File.cpp @@ -1,31 +0,0 @@ -#include - -namespace sp { -namespace io { - -File::IOInterface(const std::string& a_FilePath, unsigned int a_OpenMode) { - if (a_OpenMode & FileTag::OpenMode::In) - m_FileInput = std::make_unique(a_FilePath, std::ios::binary); - if (a_OpenMode & FileTag::OpenMode::Out) - m_FileOutput = std::make_unique(a_FilePath, std::ios::binary); -} - -File::IOInterface(File&& other) : - m_FileInput(std::move(other.m_FileInput)), m_FileOutput(std::move(other.m_FileOutput)) {} - -DataBuffer File::Read(std::size_t a_Amount) { - DataBuffer buffer; - buffer.Resize(a_Amount); - assert(m_FileInput != nullptr); - m_FileInput->read(reinterpret_cast(buffer.data()), a_Amount); - return buffer; -} - -void File::Write(const sp::DataBuffer& a_Data) { - assert(m_FileOutput != nullptr); - m_FileOutput->write(reinterpret_cast(a_Data.data()), a_Data.GetSize()); - m_FileOutput->flush(); -} - -} // namespace io -} // namespace sp diff --git a/src/sp/io/Memory.cpp b/src/sp/io/Memory.cpp index 57ffd4f..e69de29 100644 --- a/src/sp/io/Memory.cpp +++ b/src/sp/io/Memory.cpp @@ -1,16 +0,0 @@ -#include - -namespace sp { -namespace io { - -sp::DataBuffer Memory::Read(std::size_t a_Amount) { - DataBuffer data; - m_VirtualIO.ReadSome(data, a_Amount > m_VirtualIO.GetRemaining() ? m_VirtualIO.GetRemaining() : a_Amount); - return data; -} -void Memory::Write(const sp::DataBuffer& a_Data) { - m_VirtualIO << a_Data; -} - -} // namespace io -} // namespace sp diff --git a/test/test_message.cpp b/test/test_message.cpp index 5842e70..6b8a49e 100644 --- a/test/test_message.cpp +++ b/test/test_message.cpp @@ -1,7 +1,9 @@ #include -#include #include #include +#include +#include +#include #include #include @@ -24,12 +26,12 @@ using KeepAliveMessage = Message; using AllMessages = std::tuple; -class PacketHandler : public sp::GenericHandler {}; +class PacketHandler : public sp::MessageHandler {}; class MyHandler : public PacketHandler { public: - virtual void Handle(const KeepAliveMessage& msg) { - std::cout << "yo !" << "\n"; + virtual void Handle(const KeepAlivePacket& msg) { + std::cout << "I recieved a keep alive : " << msg.m_KeepAlive << "\n"; } }; @@ -37,8 +39,10 @@ using PacketDispatcher = sp::MessageDispatcher; using PacketFactory = sp::MessageFactory; +using PacketStream = sp::MessageStream; + int main() { - KeepAliveMessage m{5UL}; + KeepAliveMessage m{69UL}; // dispatch tests @@ -56,9 +60,23 @@ int main() { std::ofstream file {"test.bin"}; - message->Write(file); + PacketStream p(std::make_shared(file)); + + p.WriteMessage(m); + + file.flush(); + + std::ifstream file2 {"test.bin"}; + + PacketStream p2(std::make_shared(file2)); + + auto message2 = p2.ReadMessage(); + + d.Dispatch(*message2); + + // message->Write(file); // file << std::endl; - m.Write(file); + // m.Write(file); // file << std::endl; // message->Read(file); return 0;