From 4312de828e8f759a9a61e51fdad4a3cad015c46c Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 3 Feb 2016 18:44:03 +0100 Subject: [PATCH] Network: Add NetPacket class Former-commit-id: 0c5acdbf9313621dddd3dcee23c6f85f46c27012 --- include/Nazara/Network/NetPacket.hpp | 71 +++++++++++++ include/Nazara/Network/NetPacket.inl | 20 ++++ src/Nazara/Network/NetPacket.cpp | 147 +++++++++++++++++++++++++++ src/Nazara/Network/Network.cpp | 8 ++ 4 files changed, 246 insertions(+) create mode 100644 include/Nazara/Network/NetPacket.hpp create mode 100644 include/Nazara/Network/NetPacket.inl create mode 100644 src/Nazara/Network/NetPacket.cpp diff --git a/include/Nazara/Network/NetPacket.hpp b/include/Nazara/Network/NetPacket.hpp new file mode 100644 index 000000000..ff69fb2db --- /dev/null +++ b/include/Nazara/Network/NetPacket.hpp @@ -0,0 +1,71 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_NETPACKET_HPP +#define NAZARA_NETPACKET_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_NETWORK_API NetPacket : public ByteStream + { + friend class Network; + + public: + NetPacket(); + NetPacket(UInt16 netCode, std::size_t sizeHint = 0); + NetPacket(UInt16 netCode, const void* ptr, std::size_t size); + NetPacket(const NetPacket&) = delete; + NetPacket(NetPacket&&) = default; + ~NetPacket(); + + inline UInt16 GetNetCode() const; + + virtual void OnReceive(UInt16 netCode, const void* data, std::size_t size); + virtual const void* OnSend(std::size_t* newSize) const; + + void Reset(); + void Reset(UInt16 netCode, std::size_t sizeHint = 0); + void Reset(UInt16 netCode, const void* ptr, std::size_t size); + + inline void SetNetCode(UInt16 netCode); + + NetPacket& operator=(const NetPacket&) = delete; + NetPacket& operator=(NetPacket&&) = default; + + static bool DecodeHeader(const void* data, UInt16* packetSize, UInt16* netCode); + static bool EncodeHeader(void* data, UInt16 packetSize, UInt16 netCode); + + static constexpr std::size_t HeaderSize = sizeof(UInt16) + sizeof(UInt16); //< PacketSize + NetCode + + private: + void OnEmptyStream() override; + + void FreeStream(); + void InitStream(std::size_t sizeHint, UInt64 cursorPos, UInt32 openMode); + + static bool Initialize(); + static void Uninitialize(); + + std::unique_ptr m_buffer; + MemoryStream m_memoryStream; + UInt16 m_netCode; + + static std::unique_ptr s_availableBuffersMutex; + static std::vector>> s_availableBuffers; + }; +} + +#include + +#endif // NAZARA_NETPACKET_HPP diff --git a/include/Nazara/Network/NetPacket.inl b/include/Nazara/Network/NetPacket.inl new file mode 100644 index 000000000..62675af69 --- /dev/null +++ b/include/Nazara/Network/NetPacket.inl @@ -0,0 +1,20 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +namespace Nz +{ + inline UInt16 NetPacket::GetNetCode() const + { + return m_netCode; + } + + inline void NetPacket::SetNetCode(UInt16 netCode) + { + m_netCode = netCode; + } +} + +#include diff --git a/src/Nazara/Network/NetPacket.cpp b/src/Nazara/Network/NetPacket.cpp new file mode 100644 index 000000000..bf3b91618 --- /dev/null +++ b/src/Nazara/Network/NetPacket.cpp @@ -0,0 +1,147 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +namespace Nz +{ + NetPacket::NetPacket() : + m_netCode(NetCode_Invalid) + { + } + + NetPacket::NetPacket(UInt16 netCode, std::size_t sizeHint) + { + Reset(netCode, sizeHint); + } + + NetPacket::NetPacket(UInt16 netCode, const void* ptr, std::size_t size) + { + Reset(netCode, ptr, size); + } + + NetPacket::~NetPacket() + { + FreeStream(); + } + + void NetPacket::OnReceive(UInt16 netCode, const void* data, std::size_t size) + { + Reset(netCode, data, size); + } + + const void* NetPacket::OnSend(std::size_t* newSize) const + { + NazaraAssert(newSize, "Invalid size pointer"); + NazaraAssert(m_netCode != NetCode_Invalid, "Invalid NetCode"); + + std::size_t size = m_buffer->GetSize(); + if (!EncodeHeader(m_buffer->GetBuffer(), static_cast(size), m_netCode)) + { + NazaraError("Failed to encode packet header"); + return nullptr; + } + + *newSize = size; + return m_buffer->GetBuffer(); + } + + void NetPacket::Reset() + { + FreeStream(); + } + + void NetPacket::Reset(UInt16 netCode, std::size_t sizeHint) + { + InitStream(HeaderSize + sizeHint, HeaderSize, OpenMode_WriteOnly); + m_netCode = netCode; + } + + void NetPacket::Reset(UInt16 netCode, const void* ptr, std::size_t size) + { + InitStream(HeaderSize + size, HeaderSize, OpenMode_ReadOnly); + m_buffer->Resize(HeaderSize + size); + std::memcpy(m_buffer->GetBuffer() + HeaderSize, ptr, size); + + m_netCode = netCode; + } + + bool NetPacket::DecodeHeader(const void* data, UInt16* packetSize, UInt16* netCode) + { + MemoryView stream(data, HeaderSize); + + SerializationContext context; + context.stream = &stream; + + return Unserialize(context, packetSize) && Unserialize(context, netCode); + } + + bool NetPacket::EncodeHeader(void* data, UInt16 packetSize, UInt16 netCode) + { + MemoryView stream(data, HeaderSize); + + SerializationContext context; + context.stream = &stream; + + return Serialize(context, packetSize) && Serialize(context, netCode); + } + + void NetPacket::OnEmptyStream() + { + Reset(0); + } + + void NetPacket::FreeStream() + { + if (!m_buffer) + return; + + std::size_t size = m_buffer->GetSize(); + + Nz::LockGuard lock(*s_availableBuffersMutex); + s_availableBuffers.emplace_back(std::make_pair(size, std::move(m_buffer))); + } + + void NetPacket::InitStream(std::size_t sizeHint, UInt64 cursorPos, UInt32 openMode) + { + { + Nz::LockGuard lock(*s_availableBuffersMutex); + + FreeStream(); //< In case it wasn't released yet + + if (!s_availableBuffers.empty()) + { + m_buffer = std::move(s_availableBuffers.back().second); + s_availableBuffers.pop_back(); + } + } + + if (!m_buffer) + m_buffer = std::make_unique(); + + m_buffer->Resize(static_cast(cursorPos)); + m_memoryStream.SetBuffer(m_buffer.get(), openMode); + m_memoryStream.SetCursorPos(cursorPos); + SetStream(&m_memoryStream); + } + + bool NetPacket::Initialize() + { + s_availableBuffersMutex = std::make_unique(); + return true; + } + + void NetPacket::Uninitialize() + { + s_availableBuffers.clear(); + s_availableBuffersMutex.reset(); + } + + std::unique_ptr NetPacket::s_availableBuffersMutex; + std::vector>> NetPacket::s_availableBuffers; +} diff --git a/src/Nazara/Network/Network.cpp b/src/Nazara/Network/Network.cpp index d2f0d0d51..72fa76517 100644 --- a/src/Nazara/Network/Network.cpp +++ b/src/Nazara/Network/Network.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #if defined(NAZARA_PLATFORM_WINDOWS) @@ -48,6 +49,12 @@ namespace Nz return false; } + if (!NetPacket::Initialize()) + { + NazaraError("Failed to initialize packets"); + return false; + } + onExit.Reset(); NazaraNotice("Initialized: Network module"); @@ -73,6 +80,7 @@ namespace Nz s_moduleReferenceCounter = 0; // Uninitialize module here + NetPacket::Uninitialize(); SocketImpl::Uninitialize(); NazaraNotice("Uninitialized: Network module");