High Level API - Fully Functional

This commit is contained in:
TheDoctor
2019-10-12 19:09:55 +01:00
parent 6db271bd7e
commit ad5ff5e53e
24 changed files with 1286 additions and 4 deletions

154
HLAPI/HLAPI/HLAPI.vcxproj Normal file
View File

@ -0,0 +1,154 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\HLAPI\BitConverter.hpp" />
<ClInclude Include="..\..\include\HLAPI\DataReceivedEvent.hpp" />
<ClInclude Include="..\..\include\HLAPI\DisconnectedEvent.hpp" />
<ClInclude Include="..\..\include\HLAPI\InternalTags.hpp" />
<ClInclude Include="..\..\include\HLAPI\MessageQueue.hpp" />
<ClInclude Include="..\..\include\HLAPI\NetworkHeader.hpp" />
<ClInclude Include="..\..\include\HLAPI\NetworkMessage.hpp" />
<ClInclude Include="..\..\include\HLAPI\NewConnectionEvent.hpp" />
<ClInclude Include="..\..\include\HLAPI\Server.hpp" />
<ClInclude Include="..\..\include\HLAPI\TcpConnection.hpp" />
<ClInclude Include="..\..\include\HLAPI\TcpConnectionHandler.hpp" />
<ClInclude Include="..\..\include\HLAPI\TcpServer.hpp" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\HLAPI\main.cpp" />
<ClCompile Include="..\..\src\HLAPI\MessageQueue.cpp" />
<ClCompile Include="..\..\src\HLAPI\NetworkMessage.cpp" />
<ClCompile Include="..\..\src\HLAPI\Server.cpp" />
<ClCompile Include="..\..\src\HLAPI\TcpConnection.cpp" />
<ClCompile Include="..\..\src\HLAPI\TcpConnectionHandler.cpp" />
<ClCompile Include="..\..\src\HLAPI\TcpServer.cpp" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{989D0F55-C4B9-44D2-AD2B-DD7E1AAABFC1}</ProjectGuid>
<RootNamespace>HLAPI</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>D:\VoidNet\include\HLAPI;D:\VoidNet\include</AdditionalIncludeDirectories>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<AdditionalDependencies>D:\VoidNet\VoidNetVS\x64\Debug\VoidNetVS.lib;WS2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="include">
<UniqueIdentifier>{a941a71f-2121-4d2f-87f9-58bcadbeb98b}</UniqueIdentifier>
</Filter>
<Filter Include="src">
<UniqueIdentifier>{1c087ed8-3cca-4254-836f-10fb70fda154}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\HLAPI\BitConverter.hpp">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\HLAPI\DataReceivedEvent.hpp">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\HLAPI\DisconnectedEvent.hpp">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\HLAPI\InternalTags.hpp">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\HLAPI\MessageQueue.hpp">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\HLAPI\NetworkHeader.hpp">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\HLAPI\NetworkMessage.hpp">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\HLAPI\NewConnectionEvent.hpp">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\HLAPI\Server.hpp">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\HLAPI\TcpConnection.hpp">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\HLAPI\TcpConnectionHandler.hpp">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\..\include\HLAPI\TcpServer.hpp">
<Filter>include</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\HLAPI\main.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\..\src\HLAPI\MessageQueue.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\..\src\HLAPI\NetworkMessage.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\..\src\HLAPI\Server.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\..\src\HLAPI\TcpConnection.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\..\src\HLAPI\TcpConnectionHandler.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\..\src\HLAPI\TcpServer.cpp">
<Filter>src</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -1,4 +1,4 @@
#include "Utility.hpp"
#include "Util.hpp"
#include <iostream>

View File

@ -1,12 +1,14 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25123.0
# Visual Studio Version 16
VisualStudioVersion = 16.0.29326.143
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VoidNetVS", "VoidNetVS\VoidNetVS.vcxproj", "{5172321E-CCB0-4A77-9F3D-FAAF0084F434}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tests", "..\TestsVS\Tests\Tests.vcxproj", "{41663B22-3949-4570-9AB5-309363EAD56F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HLAPI", "..\HLAPI\HLAPI\HLAPI.vcxproj", "{989D0F55-C4B9-44D2-AD2B-DD7E1AAABFC1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@ -31,8 +33,19 @@ Global
{41663B22-3949-4570-9AB5-309363EAD56F}.Release|x64.Build.0 = Release|x64
{41663B22-3949-4570-9AB5-309363EAD56F}.Release|x86.ActiveCfg = Release|Win32
{41663B22-3949-4570-9AB5-309363EAD56F}.Release|x86.Build.0 = Release|Win32
{989D0F55-C4B9-44D2-AD2B-DD7E1AAABFC1}.Debug|x64.ActiveCfg = Debug|x64
{989D0F55-C4B9-44D2-AD2B-DD7E1AAABFC1}.Debug|x64.Build.0 = Debug|x64
{989D0F55-C4B9-44D2-AD2B-DD7E1AAABFC1}.Debug|x86.ActiveCfg = Debug|Win32
{989D0F55-C4B9-44D2-AD2B-DD7E1AAABFC1}.Debug|x86.Build.0 = Debug|Win32
{989D0F55-C4B9-44D2-AD2B-DD7E1AAABFC1}.Release|x64.ActiveCfg = Release|x64
{989D0F55-C4B9-44D2-AD2B-DD7E1AAABFC1}.Release|x64.Build.0 = Release|x64
{989D0F55-C4B9-44D2-AD2B-DD7E1AAABFC1}.Release|x86.ActiveCfg = Release|Win32
{989D0F55-C4B9-44D2-AD2B-DD7E1AAABFC1}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {30B0A8A0-814A-40F1-99DB-799D6ABB368C}
EndGlobalSection
EndGlobal

View File

@ -124,7 +124,7 @@
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
<LanguageStandard>stdcpplatest</LanguageStandard>
<PreprocessorDefinitions>_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>

View File

@ -0,0 +1,33 @@
#pragma once
// i want to use bitshifting but i red in stackoverflow that casting doesnt generate overhead
// now ive hit a wall
// casting vs bitshifting
#include <cstdint>
#include <cstring>
namespace std
{
class BitConverter
{
public:
template<typename T>
inline static uint8_t *ToBytes(T value)
{
uint8_t *data = new uint8_t[sizeof(T)]();
memcpy(data, &value, sizeof(T));
return data;
}
template<typename T>
inline static T FromBytes(uint8_t *data)
{
if (!data)
throw std::invalid_argument("cant have null parameter -> BitConverter::FromBytes");
T value;
memcpy(&value, data, sizeof(T));
return value;
}
};
}

View File

@ -0,0 +1,27 @@
#pragma once
#include "NetworkMessage.hpp"
namespace std::net
{
class DataReceivedEvent
{
public:
inline DataReceivedEvent(const NetworkMessage &msg)
{
SenderID = msg.GetSenderID();
DistributionMode = msg.GetDistributionMode();
DestinationID = msg.GetDestinationID();
Tag = msg.GetTag();
Data = msg.GetData<void>();
}
public:
uint32_t SenderID;
DistributionMode DistributionMode;
uint32_t DestinationID;
uint32_t Tag;
void *Data;
};
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <string>
namespace std::net
{
class DisconnectedEvent // can be processed by client and server
{
private:
DisconnectedEvent();
public:
inline DisconnectedEvent(uint32_t id, char *reason, int32_t reason_id)
: m_reason(reason)
, m_clientID(id)
, m_reasonID(reason_id)
{
}
inline DisconnectedEvent(uint32_t id, const std::string &reason, int32_t reason_id)
: m_reason(reason)
, m_clientID(id)
, m_reasonID(reason_id)
{
}
inline const std::string &GetReason() const { return m_reason; }
inline int32_t GetReasonID() const { return m_reasonID; }
inline uint32_t GetID() const { return m_clientID; }
private:
std::string m_reason;
int32_t m_reasonID;
uint32_t m_clientID;
};
}

View File

@ -0,0 +1,10 @@
#pragma once
#include <cstdint>
enum class InternalTags : uint32_t
{
Disconnect = 0xFFFFFFFF,
Connect = 0xFFFFFFFE,
AssignID = 0xFFFFFFFD
};

View File

@ -0,0 +1,43 @@
#pragma once
#include <queue>
#include <mutex>
#include "NetworkMessage.hpp"
#include "NewConnectionEvent.hpp"
#include "DisconnectedEvent.hpp"
#include "DataReceivedEvent.hpp"
namespace std::net
{
class MessageQueue
{
public:
MessageQueue()
{
}
void EnqueueMessageToSend(const NetworkMessage &msg);
void EnqueueMessageReceived(const NetworkMessage &msg);
void EnqueueDisconnection(const NetworkMessage &msg);
void EnqueueConnection(const NetworkMessage &msg);
NetworkMessage DequeueMessageToSend();
uint32_t SendSize();
private:
std::deque<NetworkMessage> m_messagesToSend;
std::deque<NewConnectionEvent> m_connectionEvents;
std::deque<DisconnectedEvent> m_disconnectedEvents;
std::deque<DataReceivedEvent> m_dataReceivedEvents;
std::mutex m_sendMutex;
std::mutex m_receivedMutex;
std::mutex m_disconnectMutex;
std::mutex m_connectionMutex;
};
}

View File

@ -0,0 +1,12 @@
#pragma once
#include <cstdint>
namespace std::net
{
class NetworkHeader
{
public:
uint32_t Size;
};
}

View File

@ -0,0 +1,95 @@
#pragma once
#include "NetworkHeader.hpp"
#include "BitConverter.hpp"
#include <cstdint>
#include <cstring>
namespace std::net
{
enum class DistributionMode : uint8_t
{
ID,
Others,
OthersAndServer,
All,
AllAndMe,
Server
};
class NetworkMessage
{
public:
NetworkMessage()
{
}
NetworkMessage(uint32_t sender, DistributionMode mode, uint32_t destinationId, uint32_t tag, void *data, uint32_t dataSize)
: m_senderID(sender)
, m_distributionMode(mode)
, m_destinationID(destinationId)
, m_tag(tag)
, m_data(data)
, m_dataSize(dataSize)
{
}
uint32_t GetSenderID() const;
DistributionMode GetDistributionMode() const;
uint32_t GetDestinationID() const;
uint32_t GetTag() const;
private:
uint32_t m_senderID = 0;
DistributionMode m_distributionMode = DistributionMode::All;
uint32_t m_destinationID = 0;
uint32_t m_tag = 0;
void *m_data = 0;
uint32_t m_dataSize = 0;
public:
template<typename T>
void SetData(T *data)
{
m_data = data;
m_dataSize = sizeof(T);
}
template<typename T>
uint8_t * SerializeData(uint32_t &size)
{
int32_t sizeOfNetHeader = sizeof(NetworkHeader);
NetworkHeader header;
header.Size = 13 + sizeOfNetHeader + sizeof(T);
uint8_t *bytes = new uint8_t[header.Size];
memcpy(bytes, &header, sizeOfNetHeader);
uint8_t *sender = BitConverter::ToBytes<uint32_t>(m_senderID); // 4
uint8_t *destination = BitConverter::ToBytes<uint32_t>(m_destinationID); // 4
uint8_t *tag = BitConverter::ToBytes<uint32_t>(m_tag); // 4
memcpy(bytes + sizeOfNetHeader, sender, 4);
bytes[sizeOfNetHeader + 4] = (uint8_t)m_distributionMode;
memcpy(bytes + sizeOfNetHeader + 5, destination, 4);
memcpy(bytes + sizeOfNetHeader + 9, tag, 4);
memcpy(bytes + 13 + sizeOfNetHeader, m_data, sizeof(T));
size = header.Size;
return bytes;
}
uint8_t *SerializeData(uint32_t &size);
void Deserialize(uint8_t *data, uint32_t size);
template<typename T>
T *GetData() const
{
return (T*)m_data;
}
};
}

View File

@ -0,0 +1,18 @@
#pragma once
namespace std::net
{
class NewConnectionEvent
{
public:
inline NewConnectionEvent(uint32_t id, void *data)
: m_id(id)
, m_data(data)
{
}
private:
uint32_t m_id;
void *m_data;
};
}

26
include/HLAPI/Server.hpp Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include <Net.hpp>
#include <memory>
namespace std::net
{
class TcpServer;
class MessageQueue;
class Server
{
public:
Server(uint32_t max_connections = 20, uint16_t port = DEFAULT_SERVER_PORT);
void Start();
void Stop();
private:
std::shared_ptr<std::net::TcpServer> m_tcpServer;
std::shared_ptr<MessageQueue> m_queue;
};
}

View File

@ -0,0 +1,40 @@
#pragma once
#include <functional>
#include "TcpClient.hpp"
#include "NetworkMessage.hpp"
namespace std::net
{
class TcpConnection
{
public:
friend class TcpConnectionHandler;
TcpConnection(TcpClient *client);
std::shared_ptr<TcpClient> GetClient();
uint32_t GetID();
void SetID(uint32_t id);
template<typename T>
void SendMessage(DistributionMode mode, uint32_t destinationId, uint32_t tag, void *data)
{
NetworkMessage msg(m_id, mode, destinationId, tag, data, sizeof(T));
}
void ReceiveData();
std::function<void(uint32_t, DistributionMode, uint32_t, uint32_t, void*)> DataReceivedEvent;
std::function<void(uint32_t, std::string, int32_t)> DisconnectedEvent;
std::function<void(uint32_t, void*)> NewConnectionEvent;
private:
bool sendMessage(NetworkMessage &msg);
std::shared_ptr<TcpClient> m_client;
uint32_t m_id;
};
}

View File

@ -0,0 +1,63 @@
#pragma once
#include <mutex>
#include <atomic>
#include <queue>
#include <TcpListener.hpp>
#include <TcpConnection.hpp>
//#include <BaseLibrary/SpinMutex.hpp>
namespace std::net
{
class MessageQueue;
class TcpConnection;
class Server;
namespace sockets
{
class TcpListener;
}
}
namespace std::net
{
class TcpConnectionHandler
{
friend class std::net::Server;
public:
TcpConnectionHandler(std::shared_ptr<TcpListener> listener_ptr);
~TcpConnectionHandler();
void Start();
void Stop();
void AddClient(std::shared_ptr<TcpConnection> &c);
void SetMaxConnections(uint32_t max_connections);
uint32_t GetAvailableID();
private:
void HandleReceiveMsgAndConns();
void HandleSend();
void HandleReceiveMsgAndConnsThreaded();
void HandleSendThreaded();
private:
std::vector<std::shared_ptr<TcpConnection>> m_list;
std::mutex m_listMutex;
uint32_t m_maxConnections;
std::thread m_receiveThread;
std::thread m_sendThread;
std::atomic_bool m_run;
std::shared_ptr<MessageQueue> m_queue;
std::shared_ptr<TcpListener> m_listenerPtr;
};
}

View File

@ -0,0 +1,31 @@
#pragma once
#include <atomic>
#include "TcpListener.hpp"
namespace std::net
{
class Server;
class TcpConnectionHandler;
class TcpServer
{
friend class std::net::Server;
public:
TcpServer(uint32_t max_connections, uint16_t port = DEFAULT_SERVER_PORT);
void Start();
void Stop();
private:
std::shared_ptr<TcpListener> listener;
uint32_t m_maxConnections;
uint16_t m_port;
std::atomic_bool m_run;
std::shared_ptr<std::net::TcpConnectionHandler> m_connectionHandler;
};
}

View File

@ -0,0 +1,52 @@
#include "MessageQueue.hpp"
namespace std::net
{
void MessageQueue::EnqueueMessageToSend(const NetworkMessage & msg)
{
m_sendMutex.lock();
m_messagesToSend.emplace_back(msg);
m_sendMutex.unlock();
}
void MessageQueue::EnqueueMessageReceived(const NetworkMessage & msg)
{
m_receivedMutex.lock();
DataReceivedEvent ev(msg);
m_dataReceivedEvents.push_back(ev);
m_receivedMutex.unlock();
}
void MessageQueue::EnqueueDisconnection(const NetworkMessage & msg)
{
m_disconnectMutex.lock();
//std::unique_ptr<DisconnectedEvent> ev(((NetworkMessage)msg).GetData<DisconnectedEvent>());
//m_disconnectedEvents.push_back(*(ev.get()));
m_disconnectMutex.unlock();
}
void MessageQueue::EnqueueConnection(const NetworkMessage & msg)
{
m_connectionMutex.lock();
NewConnectionEvent ev(msg.GetSenderID(), msg.GetData<void>());
m_connectionEvents.push_back(ev);
m_connectionMutex.unlock();
}
NetworkMessage MessageQueue::DequeueMessageToSend()
{
m_sendMutex.lock();
NetworkMessage msg = m_messagesToSend.front();
m_messagesToSend.erase(m_messagesToSend.begin() + 1);
m_sendMutex.unlock();
return msg;
}
uint32_t MessageQueue::SendSize()
{
m_sendMutex.lock();
uint32_t size = m_messagesToSend.size();
m_sendMutex.unlock();
return size;
}
}

View File

@ -0,0 +1,63 @@
#include "NetworkMessage.hpp"
namespace std::net
{
uint32_t NetworkMessage::GetSenderID() const
{
return m_senderID;
}
DistributionMode NetworkMessage::GetDistributionMode() const
{
return m_distributionMode;
}
uint32_t NetworkMessage::GetDestinationID() const
{
return m_destinationID;
}
uint32_t NetworkMessage::GetTag() const
{
return m_tag;
}
uint8_t *NetworkMessage::SerializeData(uint32_t &size)
{
int32_t sizeOfNetHeader = sizeof(NetworkHeader);
NetworkHeader header;
header.Size = 13 + sizeOfNetHeader + m_dataSize;
uint8_t *bytes = new uint8_t[header.Size];
memcpy(bytes, &header, sizeOfNetHeader);
uint8_t *sender = BitConverter::ToBytes<uint32_t>(m_senderID); // 4
uint8_t *destination = BitConverter::ToBytes<uint32_t>(m_destinationID); // 4
uint8_t *tag = BitConverter::ToBytes<uint32_t>(m_tag); // 4
memcpy(bytes + sizeOfNetHeader, sender, 4);
bytes[sizeOfNetHeader + 4] = (uint8_t)m_distributionMode;
memcpy(bytes + sizeOfNetHeader + 5, destination, 4);
memcpy(bytes + sizeOfNetHeader + 9, tag, 4);
memcpy(bytes + 13 + sizeOfNetHeader, m_data, m_dataSize);
size = header.Size;
return bytes;
}
void NetworkMessage::Deserialize(uint8_t *data, uint32_t size)
{
NetworkHeader buffer;
uint32_t sizeOfNetHeader = sizeof(NetworkHeader);
memcpy(&(buffer), data, sizeOfNetHeader);
memcpy(&(m_senderID), data + 4 + sizeOfNetHeader, 4);
m_distributionMode = (DistributionMode)data[8 + sizeOfNetHeader];
memcpy(&(m_destinationID), data + 5 + sizeOfNetHeader, 4);
memcpy(&(m_tag), data + 9 + sizeOfNetHeader, 4);
m_data = data + 13 + sizeOfNetHeader;
}
}

25
src/HLAPI/Server.cpp Normal file
View File

@ -0,0 +1,25 @@
#include "Server.hpp"
#include "MessageQueue.hpp"
#include "TcpServer.hpp"
//#include "UdpServer.hpp
namespace std::net
{
Server::Server(uint32_t max_connections, uint16_t port)
{
m_tcpServer = std::make_shared<std::net::TcpServer>(max_connections, port);
m_queue = std::make_shared<MessageQueue>();
//m_tcpServer->m_connectionHandler->m_queue = m_queue;
}
void Server::Start()
{
m_tcpServer->Start();
}
void Server::Stop()
{
m_tcpServer->Stop();
}
}

View File

@ -0,0 +1,72 @@
#include "TcpConnection.hpp"
#include "InternalTags.hpp"
namespace std::net
{
TcpConnection::TcpConnection(TcpClient * client)
: m_client(client)
{
}
std::shared_ptr<TcpClient> TcpConnection::GetClient()
{
return m_client;
}
uint32_t TcpConnection::GetID()
{
return m_id;
}
void TcpConnection::SetID(uint32_t id)
{
m_id = id;
}
bool TcpConnection::sendMessage(NetworkMessage & msg)
{
uint32_t size;
uint8_t *data = msg.SerializeData(size);
int32_t sent;
return m_client->Send(data, size, sent);
}
void TcpConnection::ReceiveData()
{
std::unique_ptr<uint8_t> header(new uint8_t[sizeof(NetworkHeader*)]());
int32_t read;
if (!m_client->Recv(header.get(), sizeof(NetworkHeader*), read))
return;
if (read == sizeof(NetworkHeader*))
{
std::unique_ptr<NetworkHeader> net_header((NetworkHeader*)header.get());
std::unique_ptr<uint8_t> buffer(new uint8_t[net_header->Size]());
int32_t read;
if (!m_client->Recv(buffer.get(), net_header->Size, read))
{
if (read != net_header->Size)
return; // wrong message?
NetworkMessage msg;
msg.Deserialize(buffer.get(), net_header->Size);
if (msg.GetTag() == (uint32_t)InternalTags::Disconnect)
{
//DisconnectedEvent(msg.m_senderID, );
}
else if (msg.GetTag() == (uint32_t)InternalTags::Connect)
NewConnectionEvent(msg.GetSenderID(), msg.GetData<void>());
else
DataReceivedEvent(msg.GetSenderID(), msg.GetDistributionMode(), msg.GetDestinationID(), msg.GetTag(), msg.GetData<void>());
}
}
else // wrong message
{
return;
}
}
}

View File

@ -0,0 +1,306 @@
#include "TcpConnectionHandler.hpp"
#include "DisconnectedEvent.hpp"
#include "NewConnectionEvent.hpp"
#include "InternalTags.hpp"
#include "NetworkMessage.hpp"
#include "MessageQueue.hpp"
#include "TcpConnection.hpp"
#include "TcpListener.hpp"
#include <chrono>
namespace std::net
{
TcpConnectionHandler::TcpConnectionHandler(std::shared_ptr<TcpListener> listener_ptr)
: m_run(false)
, m_listenerPtr(listener_ptr)
, m_queue(new MessageQueue())
{
}
TcpConnectionHandler::~TcpConnectionHandler()
{
m_run.exchange(false);
}
void TcpConnectionHandler::Start()
{
m_run.exchange(true);
std::thread receive_thread(&TcpConnectionHandler::HandleReceiveMsgAndConnsThreaded, this);
m_receiveThread.swap(receive_thread);
//std::thread send_thread(&TcpConnectionHandler::HandleSendThreaded, this);
//m_sendThread.swap(send_thread);
}
void TcpConnectionHandler::Stop()
{
m_run.exchange(false);
}
void TcpConnectionHandler::AddClient(std::shared_ptr<TcpConnection> &c)
{
uint32_t id = GetAvailableID();
if (id == -1)
{
// this can be handled just by the server
// what if the server owner wants to know if a user wanted to join but couldnt
DisconnectedEvent disconnected_event(id, "Server Full", -1);
std::shared_ptr<TcpClient> client = c->GetClient();
/*int32_t size = 0;
uint8_t *buffer = disconnected_event.Serialize(size);
int32_t sent = 0;
client->Send(buffer, size, sent);*/
client->Close();
}
c->SetID(id);
uint32_t *id_ptr = &id;
NetworkMessage msg(0, DistributionMode::ID, id, (uint32_t)InternalTags::AssignID, id_ptr, sizeof(id_ptr));
std::this_thread::sleep_for(std::chrono::milliseconds(50));
uint32_t serialized_size;
uint8_t *serialized_data = msg.SerializeData<uint32_t>(serialized_size);
int32_t sent;
if (!c->GetClient()->Send(serialized_data, serialized_size, sent))
{
//couldnt send
return;
}
m_listMutex.lock();
m_list.push_back(c);
m_listMutex.unlock();
m_queue->EnqueueConnection(msg);
}
uint32_t TcpConnectionHandler::GetAvailableID()
{
for (int i = 1; i <= m_maxConnections; i++)
{
bool flag = true;
m_listMutex.lock();
for (int k = 0; k < m_list.size(); k++)
{
if (m_list.at(k)->GetID() == i)
flag = false;
}
m_listMutex.unlock();
if (flag)
return i;
}
//throw OutOfRangeException("Out of IDs to allocate - clients = max connections", "NewConnectionEventPool");
return -1;
}
void TcpConnectionHandler::SetMaxConnections(uint32_t max_connections)
{
m_maxConnections = max_connections;
}
void TcpConnectionHandler::HandleReceiveMsgAndConns()
{
// https://www.ibm.com/support/knowledgecenter/en/ssw_i5_54/rzab6/poll.htm
std::vector<pollfd> poll_fds;
pollfd master_fd;
master_fd.fd = m_listenerPtr->m_socket->GetNativeSocket();
master_fd.events = POLLRDNORM;
poll_fds.emplace_back(master_fd);
for (size_t i = 0; i < m_list.size(); i++)
{
pollfd client_fd;
client_fd.fd = m_list.at(i)->m_client->m_socket->GetNativeSocket();
client_fd.events = POLLRDNORM;
poll_fds.emplace_back(client_fd);
}
int res = poll(poll_fds.data(), poll_fds.size(), -1);
if (res < 0)
{
//poll error
}
//should never timeout because its infinite (negative)
//if (res == 0)
//{
//timeout
//}
for (int i = 0; i < poll_fds.size(); i++)
{
if (poll_fds.at(i).revents == 0)
continue;
if (poll_fds[i].revents != POLLRDNORM)
{
continue;
}
if (poll_fds.at(i).fd == m_listenerPtr->m_socket->GetNativeSocket())
{
TcpClient *c = m_listenerPtr->AcceptClient();
if (c)
{
std::shared_ptr<TcpConnection> connection = std::make_shared<TcpConnection>(c);
AddClient(connection);
break;
}
}
else // not the listening socket
{
SOCKET c = poll_fds.at(i).fd;
std::unique_ptr<uint8_t> header(new uint8_t[sizeof(NetworkHeader*)]());
int32_t read;
if ((read = recv(c, (char*)header.get(), sizeof(NetworkHeader*), 0)) != sizeof(NetworkHeader*))
continue;
std::unique_ptr<NetworkHeader> net_header((NetworkHeader*)header.get());
std::unique_ptr<uint8_t> buffer(new uint8_t[net_header->Size]());
if ((read = recv(c, (char*)buffer.get(), net_header->Size, 0)) == net_header->Size)
{
NetworkMessage msg;
msg.Deserialize(buffer.get(), net_header->Size);
if (msg.GetTag() == (uint32_t)InternalTags::Disconnect)
m_queue->EnqueueDisconnection(msg);
else if (msg.GetTag() == (uint32_t)InternalTags::Connect)
m_queue->EnqueueConnection(msg);
else
m_queue->EnqueueMessageReceived(msg);
}
else
continue;
}
}
}
void TcpConnectionHandler::HandleSend()
{
if (m_queue->SendSize() > 0)
{
NetworkMessage msg = m_queue->DequeueMessageToSend();
uint32_t size;
std::unique_ptr<uint8_t> data(msg.SerializeData(size));
if (msg.GetDistributionMode() == DistributionMode::Others)
{
m_listMutex.lock();
for (int i = 0; i < m_list.size(); i++)
{
std::shared_ptr<TcpConnection> c = m_list.at(i);
if (c->GetID() != msg.GetSenderID())
{
int32_t sent;
if (!c->GetClient()->Send(data.get(), size, sent))
{
// it failed - retry? or just disconnect right in the first try
}
}
}
m_listMutex.unlock();
}
else if (msg.GetDistributionMode() == DistributionMode::OthersAndServer)
{
m_listMutex.lock();
for (int i = 0; i < m_list.size(); i++)
{
std::shared_ptr<TcpConnection> c = m_list.at(i);
if (c->GetID() != msg.GetSenderID())
{
int32_t sent;
if (!c->GetClient()->Send(data.get(), size, sent))
{
// it failed - retry? or just disconnect right in the first try
}
}
}
m_listMutex.unlock();
//handle to plugins too
}
else if (msg.GetDistributionMode() == DistributionMode::ID)
{
m_listMutex.lock();
for (int i = 0; i < m_list.size(); i++)
{
std::shared_ptr<TcpConnection> c = m_list.at(i);
if (c->GetID() == msg.GetSenderID())
{
int32_t sent;
if (!c->GetClient()->Send(data.get(), size, sent))
{
// it failed - retry? or just disconnect right in the first try
}
}
}
m_listMutex.unlock();
}
else if (msg.GetDistributionMode() == DistributionMode::All)
{
m_listMutex.lock();
for (int i = 0; i < m_list.size(); i++)
{
std::shared_ptr<TcpConnection> c = m_list.at(i);
int32_t sent;
if (!c->GetClient()->Send(data.get(), size, sent))
{
// it failed - retry? or just disconnect right in the first try
}
}
m_listMutex.unlock();
}
else if (msg.GetDistributionMode() == DistributionMode::AllAndMe)
{
m_listMutex.lock();
for (int i = 0; i < m_list.size(); i++)
{
std::shared_ptr<TcpConnection> c = m_list.at(i);
int32_t sent;
if (!c->GetClient()->Send(data.get(), size, sent))
{
// it failed - retry? or just disconnect right in the first try
}
}
m_listMutex.unlock();
//handle to plugins too
}
else if (msg.GetDistributionMode() == DistributionMode::Server)
{
//handle just in plugins
}
}
}
void TcpConnectionHandler::HandleReceiveMsgAndConnsThreaded()
{
while (m_run.load())
{
HandleReceiveMsgAndConns();
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
}
void TcpConnectionHandler::HandleSendThreaded()
{
while (m_run.load())
{
HandleSend();
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
}
}

33
src/HLAPI/TcpServer.cpp Normal file
View File

@ -0,0 +1,33 @@
#include "TcpServer.hpp"
#include "TcpConnection.hpp"
#include "TcpSocketBuilder.hpp"
#include "TcpClient.hpp"
#include "TcpConnectionHandler.hpp"
namespace std::net
{
TcpServer::TcpServer(uint32_t max_connections, uint16_t port)
: m_maxConnections(max_connections)
, m_port(port)
, m_run(false)
{
if (max_connections == 0 || port == 0)
throw std::invalid_argument("TcpServer::TcpServer()");
listener = std::shared_ptr<TcpListener>(TcpSocketBuilder().AsReusable().Bind(IPAddress(0, 0, 0, 0, port)).Listening().BuildListener().release());
m_connectionHandler = std::make_shared<std::net::TcpConnectionHandler>(listener);
m_connectionHandler->SetMaxConnections(max_connections);
}
void TcpServer::Start()
{
m_run = true;
m_connectionHandler->Start();
}
void TcpServer::Stop()
{
m_run.exchange(false);
}
}

58
src/HLAPI/main.cpp Normal file
View File

@ -0,0 +1,58 @@
#include "Init.hpp"
#include "Server.hpp"
#include "BitConverter.hpp"
#include "TcpClient.hpp"
#include "InternalTags.hpp"
#include "NetworkMessage.hpp"
#include <iostream>
int main()
{
std::net::Initialize();
std::net::Server server(100);
server.Start();
std::net::TcpClient client;
std::net::IPAddress ip("127.0.0.1");
client.Connect(ip);
std::net::TcpClient client2;
client2.Connect(ip);
while (true)
{
uint32_t data_size;
while (client.HasPendingData(data_size))
{
std::net::NetworkMessage message;
uint8_t *bytes = new uint8_t[data_size]();
int32_t read;
client.Recv(bytes, data_size, read);
message.Deserialize(bytes, data_size);
uint32_t id = std::BitConverter::FromBytes<uint32_t>((uint8_t*)(message.GetData<void>()));
if (message.GetTag() == (uint32_t)InternalTags::AssignID)
std::cout << id << std::endl;
}
while (client2.HasPendingData(data_size))
{
std::net::NetworkMessage message2;
uint8_t* bytes2 = new uint8_t[data_size]();
int32_t read2;
client2.Recv(bytes2, data_size, read2);
message2.Deserialize(bytes2, data_size);
uint32_t id2 = std::BitConverter::FromBytes<uint32_t>((uint8_t*)(message2.GetData<void>()));
if (message2.GetTag() == (uint32_t)InternalTags::AssignID)
std::cout << id2 << std::endl;
}
}
}