Add basic network classes and message pooling

This commit is contained in:
Damian Korczowski
2021-03-07 23:50:04 +01:00
parent 4072796e54
commit 8f653fa699
11 changed files with 331 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
API_INTERFACE() class FLAXENGINE_API INetworkDriver
{
public:
virtual void Initialize(const NetworkConfig& config) = 0;
virtual void Dispose() = 0;
virtual void Listen() = 0;
virtual void SendMessage(const NetworkMessage* message, void* targets) = 0; // TODO
};

View File

@@ -0,0 +1,18 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Scripting/ScriptingType.h"
API_ENUM() enum class NetworkChannelType
{
None = 0,
Unreliable,
UnreliableOrdered,
UnreliableFragmented,
Reliable,
ReliableOrdered,
ReliableFragmented
};

View File

@@ -0,0 +1,15 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
API_STRUCT() struct FLAXENGINE_API NetworkConfig
{
public:
INetworkDriver* NetworkDriver = nullptr;
public:
uint16 ConnectionsLimit = 32;
uint16 Port = 7777;
uint16 MessageSize = 1500; // MTU
uint16 MessagePoolSize = 2048; // (RX and TX)
};

View File

@@ -0,0 +1,4 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "NetworkConnection.h"

View File

@@ -0,0 +1,11 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Scripting/ScriptingType.h"
API_STRUCT() struct FLAXENGINE_API NetworkConnection
{
public:
uint32 ConnectionId;
};

View File

@@ -0,0 +1,25 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Scripting/ScriptingType.h"
API_ENUM() enum class NetworkEventType
{
Undefined = 0,
ConnectionRequest,
Connected,
Disconnected,
Message,
Error
};
API_STRUCT() struct FLAXENGINE_API NetworkEvent
{
public:
API_FIELD();
NetworkEventType EventType;
// TODO
};

View File

@@ -0,0 +1,135 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "NetworkManager.h"
#include "NetworkMessage.h"
#include "NetworkConfig.h"
#include "INetworkDriver.h"
#include "Engine/Core/Core.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Core/Math/Math.h"
#include "Engine/Platform/CPUInfo.h"
namespace
{
NetworkConfig Config;
INetworkDriver* NetworkDriver = nullptr;
uint8* MessageBuffer = nullptr;
Array<uint32, HeapAllocation> MessagePool;
}
bool NetworkManager::Initialize(const NetworkConfig& config)
{
Config = config;
ASSERT(NetworkDriver == nullptr);
ASSERT(Config.NetworkDriver);
ASSERT(Config.ConnectionsLimit > 0);
ASSERT(Config.MessageSize > 32); // TODO: Adjust this, not sure what the lowest limit should be.
ASSERT(Config.MessagePoolSize > 128);
// Setup messages
CreateMessageBuffers();
MessagePool.Clear();
MessagePool.Resize(Config.MessagePoolSize);
// Warmup message pool
for(uint32 messageId = Config.MessagePoolSize; messageId > 0; messageId --)
MessagePool.Push(messageId);
// Setup network driver
NetworkDriver = Config.NetworkDriver;
NetworkDriver->Initialize(Config);
return false;
}
void NetworkManager::Shutdown()
{
SAFE_DISPOSE(NetworkDriver);
DisposeMessageBuffers();
}
bool NetworkManager::Listen()
{
// TODO
return false;
}
void NetworkManager::Connect()
{
// TODO
}
void NetworkManager::Disconnect()
{
// TODO
}
NetworkMessage NetworkManager::BeginSendMessage()
{
return CreateMessage();
}
void NetworkManager::AbortSendMessage(const NetworkMessage& message)
{
ASSERT(message.IsValid());
RecycleMessage(message);
}
bool NetworkManager::EndSendMessage(NetworkChannelType channelType, const NetworkMessage& message, Array<NetworkConnection> targets)
{
ASSERT(message.IsValid());
// TODO: Send message
RecycleMessage(message);
return false;
}
NetworkMessage NetworkManager::CreateMessage()
{
ASSERT(MessagePool.Count() > 0);
const uint32 messageId = MessagePool.Pop();
uint8* messageBuffer = GetMessageBuffer(messageId);
return NetworkMessage { messageBuffer, Config.MessageSize, 0, 0 };
}
void NetworkManager::RecycleMessage(const NetworkMessage& message)
{
ASSERT(message.IsValid());
}
void NetworkManager::CreateMessageBuffers()
{
ASSERT(MessageBuffer == nullptr);
const uint32 pageSize = Platform::GetCPUInfo().PageSize;
// Calculate total size in bytes
const uint64 totalSize = static_cast<uint64>(Config.MessagePoolSize) * Config.MessageSize;
// Calculate the amount of pages that we need
const uint32 numPages = totalSize > pageSize ? Math::CeilToInt(totalSize / static_cast<double>(pageSize)) : 1;
MessageBuffer = static_cast<uint8*>(Platform::AllocatePages(numPages, pageSize));
Platform::MemorySet(MessageBuffer, 0, numPages * pageSize);
}
void NetworkManager::DisposeMessageBuffers()
{
ASSERT(MessageBuffer != nullptr);
Platform::FreePages(MessageBuffer);
MessageBuffer = nullptr;
}
uint8* NetworkManager::GetMessageBuffer(const uint32 messageId)
{
// Calculate and return the buffer slice using previously calculated slice.
return MessageBuffer + Config.MessageSize * messageId;
}

View File

@@ -0,0 +1,34 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Scripting/ScriptingType.h"
#include "Types.h"
API_CLASS(Static) class FLAXENGINE_API NetworkManager
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(NetworkManager);
public:
API_FUNCTION() static bool Initialize(const NetworkConfig& config);
API_FUNCTION() static void Shutdown();
API_FUNCTION() static bool Listen();
API_FUNCTION() static void Connect();
API_FUNCTION() static void Disconnect();
API_FUNCTION() static bool PopEvent(NetworkEvent* event);
API_FUNCTION() static NetworkMessage BeginSendMessage();
API_FUNCTION() static void AbortSendMessage(const NetworkMessage& message);
API_FUNCTION() static bool EndSendMessage(NetworkChannelType channelType, const NetworkMessage& message, Array<NetworkConnection, HeapAllocation> targets);
private:
static NetworkMessage CreateMessage();
static void RecycleMessage(const NetworkMessage& message);
static void CreateMessageBuffers();
static void DisposeMessageBuffers();
static uint8* GetMessageBuffer(uint32 messageId);
};

View File

@@ -0,0 +1,29 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "NetworkMessage.h"
void NetworkMessage::WriteBytes(uint8* bytes, const int numBytes)
{
ASSERT(Position + numBytes < BufferSize);
Platform::MemoryCopy(Buffer + Position, bytes, numBytes);
Position += numBytes;
}
void NetworkMessage::ReadBytes(uint8* bytes, const int numBytes)
{
ASSERT(Position + numBytes < BufferSize);
Platform::MemoryCopy(bytes, Buffer + Position, numBytes);
Position += numBytes;
}
void NetworkMessage::WriteUInt32(uint32 value)
{
WriteBytes(reinterpret_cast<uint8*>(&value), sizeof(uint32));
}
uint32 NetworkMessage::ReadUInt32()
{
uint32 value = 0;
ReadBytes(reinterpret_cast<uint8*>(&value), sizeof(uint32));
return value;
}

View File

@@ -0,0 +1,35 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Scripting/ScriptingType.h"
API_STRUCT() struct FLAXENGINE_API NetworkMessage
{
public:
API_FIELD()
uint8* Buffer;
API_FIELD()
uint32 BufferSize;
API_FIELD()
uint32 Length;
API_FIELD()
uint32 Position;
public:
API_FUNCTION() void WriteBytes(uint8* bytes, int numBytes);
API_FUNCTION() void ReadBytes(uint8* bytes, int numBytes);
public:
API_FUNCTION() void WriteUInt32(uint32 value); // TODO: Macro the shit out of this
API_FUNCTION() uint32 ReadUInt32();
public:
API_FUNCTION() bool IsValid() const
{
return Buffer != nullptr && BufferSize > 0;
}
};

View File

@@ -0,0 +1,12 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
enum class NetworkChannelType;
class INetworkDriver;
struct NetworkEvent;
struct NetworkConnection;
struct NetworkMessage;
struct NetworkConfig;