From ad5ff5e53e3a7e779b299c667bbd544068d1de3f Mon Sep 17 00:00:00 2001 From: TheDoctor Date: Sat, 12 Oct 2019 19:09:55 +0100 Subject: [PATCH] High Level API - Fully Functional --- HLAPI/HLAPI/HLAPI.vcxproj | 154 +++++++++++++ HLAPI/HLAPI/HLAPI.vcxproj.filters | 72 ++++++ TestsVS/Tests/Tests.cpp | 2 +- VoidNetVS/VoidNetVS.sln | 17 +- VoidNetVS/VoidNetVS/VoidNetVS.vcxproj | 2 +- include/HLAPI/BitConverter.hpp | 33 +++ include/HLAPI/DataReceivedEvent.hpp | 27 +++ include/HLAPI/DisconnectedEvent.hpp | 36 +++ include/HLAPI/InternalTags.hpp | 10 + include/HLAPI/MessageQueue.hpp | 43 ++++ include/HLAPI/NetworkHeader.hpp | 12 + include/HLAPI/NetworkMessage.hpp | 95 ++++++++ include/HLAPI/NewConnectionEvent.hpp | 18 ++ include/HLAPI/Server.hpp | 26 +++ include/HLAPI/TcpConnection.hpp | 40 ++++ include/HLAPI/TcpConnectionHandler.hpp | 63 +++++ include/HLAPI/TcpServer.hpp | 31 +++ src/HLAPI/MessageQueue.cpp | 52 +++++ src/HLAPI/NetworkMessage.cpp | 63 +++++ src/HLAPI/Server.cpp | 25 ++ src/HLAPI/TcpConnection.cpp | 72 ++++++ src/HLAPI/TcpConnectionHandler.cpp | 306 +++++++++++++++++++++++++ src/HLAPI/TcpServer.cpp | 33 +++ src/HLAPI/main.cpp | 58 +++++ 24 files changed, 1286 insertions(+), 4 deletions(-) create mode 100644 HLAPI/HLAPI/HLAPI.vcxproj create mode 100644 HLAPI/HLAPI/HLAPI.vcxproj.filters create mode 100644 include/HLAPI/BitConverter.hpp create mode 100644 include/HLAPI/DataReceivedEvent.hpp create mode 100644 include/HLAPI/DisconnectedEvent.hpp create mode 100644 include/HLAPI/InternalTags.hpp create mode 100644 include/HLAPI/MessageQueue.hpp create mode 100644 include/HLAPI/NetworkHeader.hpp create mode 100644 include/HLAPI/NetworkMessage.hpp create mode 100644 include/HLAPI/NewConnectionEvent.hpp create mode 100644 include/HLAPI/Server.hpp create mode 100644 include/HLAPI/TcpConnection.hpp create mode 100644 include/HLAPI/TcpConnectionHandler.hpp create mode 100644 include/HLAPI/TcpServer.hpp create mode 100644 src/HLAPI/MessageQueue.cpp create mode 100644 src/HLAPI/NetworkMessage.cpp create mode 100644 src/HLAPI/Server.cpp create mode 100644 src/HLAPI/TcpConnection.cpp create mode 100644 src/HLAPI/TcpConnectionHandler.cpp create mode 100644 src/HLAPI/TcpServer.cpp create mode 100644 src/HLAPI/main.cpp diff --git a/HLAPI/HLAPI/HLAPI.vcxproj b/HLAPI/HLAPI/HLAPI.vcxproj new file mode 100644 index 0000000..2ba64fb --- /dev/null +++ b/HLAPI/HLAPI/HLAPI.vcxproj @@ -0,0 +1,154 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + 16.0 + {989D0F55-C4B9-44D2-AD2B-DD7E1AAABFC1} + HLAPI + 10.0.17763.0 + + + + Application + true + v142 + MultiByte + + + Application + false + v142 + true + MultiByte + + + Application + true + v141 + MultiByte + + + Application + false + v142 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + true + D:\VoidNet\include\HLAPI;D:\VoidNet\include + stdcpplatest + + + Console + D:\VoidNet\VoidNetVS\x64\Debug\VoidNetVS.lib;WS2_32.lib;%(AdditionalDependencies) + + + + + Level3 + Disabled + true + true + + + Console + + + + + Level3 + MaxSpeed + true + true + true + true + + + Console + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + + + Console + true + true + + + + + + \ No newline at end of file diff --git a/HLAPI/HLAPI/HLAPI.vcxproj.filters b/HLAPI/HLAPI/HLAPI.vcxproj.filters new file mode 100644 index 0000000..60bef89 --- /dev/null +++ b/HLAPI/HLAPI/HLAPI.vcxproj.filters @@ -0,0 +1,72 @@ + + + + + {a941a71f-2121-4d2f-87f9-58bcadbeb98b} + + + {1c087ed8-3cca-4254-836f-10fb70fda154} + + + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + \ No newline at end of file diff --git a/TestsVS/Tests/Tests.cpp b/TestsVS/Tests/Tests.cpp index c73c4dc..aa098d5 100644 --- a/TestsVS/Tests/Tests.cpp +++ b/TestsVS/Tests/Tests.cpp @@ -1,4 +1,4 @@ -#include "Utility.hpp" +#include "Util.hpp" #include diff --git a/VoidNetVS/VoidNetVS.sln b/VoidNetVS/VoidNetVS.sln index aabb269..a340f35 100644 --- a/VoidNetVS/VoidNetVS.sln +++ b/VoidNetVS/VoidNetVS.sln @@ -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 diff --git a/VoidNetVS/VoidNetVS/VoidNetVS.vcxproj b/VoidNetVS/VoidNetVS/VoidNetVS.vcxproj index 8caf10b..5331e04 100644 --- a/VoidNetVS/VoidNetVS/VoidNetVS.vcxproj +++ b/VoidNetVS/VoidNetVS/VoidNetVS.vcxproj @@ -124,7 +124,7 @@ Disabled true ../../include - stdcpp17 + stdcpplatest _WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) diff --git a/include/HLAPI/BitConverter.hpp b/include/HLAPI/BitConverter.hpp new file mode 100644 index 0000000..9984841 --- /dev/null +++ b/include/HLAPI/BitConverter.hpp @@ -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 +#include + +namespace std +{ + class BitConverter + { + public: + template + inline static uint8_t *ToBytes(T value) + { + uint8_t *data = new uint8_t[sizeof(T)](); + memcpy(data, &value, sizeof(T)); + return data; + } + + template + 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; + } + }; +} \ No newline at end of file diff --git a/include/HLAPI/DataReceivedEvent.hpp b/include/HLAPI/DataReceivedEvent.hpp new file mode 100644 index 0000000..b758432 --- /dev/null +++ b/include/HLAPI/DataReceivedEvent.hpp @@ -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(); + } + + public: + uint32_t SenderID; + DistributionMode DistributionMode; + uint32_t DestinationID; + uint32_t Tag; + + void *Data; + }; +} \ No newline at end of file diff --git a/include/HLAPI/DisconnectedEvent.hpp b/include/HLAPI/DisconnectedEvent.hpp new file mode 100644 index 0000000..b8943db --- /dev/null +++ b/include/HLAPI/DisconnectedEvent.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include + +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; + }; +} \ No newline at end of file diff --git a/include/HLAPI/InternalTags.hpp b/include/HLAPI/InternalTags.hpp new file mode 100644 index 0000000..f5f7690 --- /dev/null +++ b/include/HLAPI/InternalTags.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +enum class InternalTags : uint32_t +{ + Disconnect = 0xFFFFFFFF, + Connect = 0xFFFFFFFE, + AssignID = 0xFFFFFFFD +}; \ No newline at end of file diff --git a/include/HLAPI/MessageQueue.hpp b/include/HLAPI/MessageQueue.hpp new file mode 100644 index 0000000..decfe76 --- /dev/null +++ b/include/HLAPI/MessageQueue.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +#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 m_messagesToSend; + + std::deque m_connectionEvents; + std::deque m_disconnectedEvents; + std::deque m_dataReceivedEvents; + + std::mutex m_sendMutex; + std::mutex m_receivedMutex; + std::mutex m_disconnectMutex; + std::mutex m_connectionMutex; + }; +} \ No newline at end of file diff --git a/include/HLAPI/NetworkHeader.hpp b/include/HLAPI/NetworkHeader.hpp new file mode 100644 index 0000000..f7ea01d --- /dev/null +++ b/include/HLAPI/NetworkHeader.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace std::net +{ + class NetworkHeader + { + public: + uint32_t Size; + }; +} \ No newline at end of file diff --git a/include/HLAPI/NetworkMessage.hpp b/include/HLAPI/NetworkMessage.hpp new file mode 100644 index 0000000..a4459da --- /dev/null +++ b/include/HLAPI/NetworkMessage.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include "NetworkHeader.hpp" +#include "BitConverter.hpp" + +#include +#include + +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 + void SetData(T *data) + { + m_data = data; + m_dataSize = sizeof(T); + } + + template + 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(m_senderID); // 4 + uint8_t *destination = BitConverter::ToBytes(m_destinationID); // 4 + uint8_t *tag = BitConverter::ToBytes(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 + T *GetData() const + { + return (T*)m_data; + } + }; +} \ No newline at end of file diff --git a/include/HLAPI/NewConnectionEvent.hpp b/include/HLAPI/NewConnectionEvent.hpp new file mode 100644 index 0000000..3a3ea37 --- /dev/null +++ b/include/HLAPI/NewConnectionEvent.hpp @@ -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; + }; +} \ No newline at end of file diff --git a/include/HLAPI/Server.hpp b/include/HLAPI/Server.hpp new file mode 100644 index 0000000..fc644d0 --- /dev/null +++ b/include/HLAPI/Server.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include + +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 m_tcpServer; + + std::shared_ptr m_queue; + }; +} \ No newline at end of file diff --git a/include/HLAPI/TcpConnection.hpp b/include/HLAPI/TcpConnection.hpp new file mode 100644 index 0000000..0225a25 --- /dev/null +++ b/include/HLAPI/TcpConnection.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include + +#include "TcpClient.hpp" + +#include "NetworkMessage.hpp" + +namespace std::net +{ + class TcpConnection + { + public: + friend class TcpConnectionHandler; + + TcpConnection(TcpClient *client); + + std::shared_ptr GetClient(); + uint32_t GetID(); + void SetID(uint32_t id); + + template + 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 DataReceivedEvent; + std::function DisconnectedEvent; + std::function NewConnectionEvent; + + private: + bool sendMessage(NetworkMessage &msg); + + std::shared_ptr m_client; + uint32_t m_id; + }; +} \ No newline at end of file diff --git a/include/HLAPI/TcpConnectionHandler.hpp b/include/HLAPI/TcpConnectionHandler.hpp new file mode 100644 index 0000000..aa666be --- /dev/null +++ b/include/HLAPI/TcpConnectionHandler.hpp @@ -0,0 +1,63 @@ +#pragma once + +#include +#include +#include + +#include +#include + +//#include + +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 listener_ptr); + ~TcpConnectionHandler(); + + void Start(); + void Stop(); + void AddClient(std::shared_ptr &c); + void SetMaxConnections(uint32_t max_connections); + + uint32_t GetAvailableID(); + + private: + void HandleReceiveMsgAndConns(); + void HandleSend(); + + void HandleReceiveMsgAndConnsThreaded(); + void HandleSendThreaded(); + + private: + std::vector> 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 m_queue; + + std::shared_ptr m_listenerPtr; + }; +} \ No newline at end of file diff --git a/include/HLAPI/TcpServer.hpp b/include/HLAPI/TcpServer.hpp new file mode 100644 index 0000000..8128000 --- /dev/null +++ b/include/HLAPI/TcpServer.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include + +#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 listener; + uint32_t m_maxConnections; + uint16_t m_port; + + std::atomic_bool m_run; + + std::shared_ptr m_connectionHandler; + }; +} \ No newline at end of file diff --git a/src/HLAPI/MessageQueue.cpp b/src/HLAPI/MessageQueue.cpp new file mode 100644 index 0000000..6b18e5f --- /dev/null +++ b/src/HLAPI/MessageQueue.cpp @@ -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 ev(((NetworkMessage)msg).GetData()); + //m_disconnectedEvents.push_back(*(ev.get())); + m_disconnectMutex.unlock(); + } + + void MessageQueue::EnqueueConnection(const NetworkMessage & msg) + { + m_connectionMutex.lock(); + NewConnectionEvent ev(msg.GetSenderID(), msg.GetData()); + 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; + } +} \ No newline at end of file diff --git a/src/HLAPI/NetworkMessage.cpp b/src/HLAPI/NetworkMessage.cpp new file mode 100644 index 0000000..42c968c --- /dev/null +++ b/src/HLAPI/NetworkMessage.cpp @@ -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(m_senderID); // 4 + uint8_t *destination = BitConverter::ToBytes(m_destinationID); // 4 + uint8_t *tag = BitConverter::ToBytes(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; + } +} \ No newline at end of file diff --git a/src/HLAPI/Server.cpp b/src/HLAPI/Server.cpp new file mode 100644 index 0000000..99d3888 --- /dev/null +++ b/src/HLAPI/Server.cpp @@ -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(max_connections, port); + m_queue = std::make_shared(); + //m_tcpServer->m_connectionHandler->m_queue = m_queue; + } + + void Server::Start() + { + m_tcpServer->Start(); + } + + void Server::Stop() + { + m_tcpServer->Stop(); + } +} \ No newline at end of file diff --git a/src/HLAPI/TcpConnection.cpp b/src/HLAPI/TcpConnection.cpp new file mode 100644 index 0000000..490f1c1 --- /dev/null +++ b/src/HLAPI/TcpConnection.cpp @@ -0,0 +1,72 @@ +#include "TcpConnection.hpp" + +#include "InternalTags.hpp" + +namespace std::net +{ + TcpConnection::TcpConnection(TcpClient * client) + : m_client(client) + { + } + + std::shared_ptr 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 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 net_header((NetworkHeader*)header.get()); + + std::unique_ptr 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()); + else + DataReceivedEvent(msg.GetSenderID(), msg.GetDistributionMode(), msg.GetDestinationID(), msg.GetTag(), msg.GetData()); + } + } + else // wrong message + { + return; + } + } +} \ No newline at end of file diff --git a/src/HLAPI/TcpConnectionHandler.cpp b/src/HLAPI/TcpConnectionHandler.cpp new file mode 100644 index 0000000..5278c0c --- /dev/null +++ b/src/HLAPI/TcpConnectionHandler.cpp @@ -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 + +namespace std::net +{ + TcpConnectionHandler::TcpConnectionHandler(std::shared_ptr 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 &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 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(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 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 connection = std::make_shared(c); + AddClient(connection); + break; + } + } + else // not the listening socket + { + SOCKET c = poll_fds.at(i).fd; + std::unique_ptr 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 net_header((NetworkHeader*)header.get()); + std::unique_ptr 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 data(msg.SerializeData(size)); + + if (msg.GetDistributionMode() == DistributionMode::Others) + { + m_listMutex.lock(); + for (int i = 0; i < m_list.size(); i++) + { + std::shared_ptr 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 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 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 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 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)); + } + } +} \ No newline at end of file diff --git a/src/HLAPI/TcpServer.cpp b/src/HLAPI/TcpServer.cpp new file mode 100644 index 0000000..778f451 --- /dev/null +++ b/src/HLAPI/TcpServer.cpp @@ -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(TcpSocketBuilder().AsReusable().Bind(IPAddress(0, 0, 0, 0, port)).Listening().BuildListener().release()); + m_connectionHandler = std::make_shared(listener); + m_connectionHandler->SetMaxConnections(max_connections); + } + + void TcpServer::Start() + { + m_run = true; + m_connectionHandler->Start(); + } + + void TcpServer::Stop() + { + m_run.exchange(false); + } +} \ No newline at end of file diff --git a/src/HLAPI/main.cpp b/src/HLAPI/main.cpp new file mode 100644 index 0000000..ac90fc3 --- /dev/null +++ b/src/HLAPI/main.cpp @@ -0,0 +1,58 @@ +#include "Init.hpp" +#include "Server.hpp" +#include "BitConverter.hpp" +#include "TcpClient.hpp" +#include "InternalTags.hpp" +#include "NetworkMessage.hpp" + +#include + +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((uint8_t*)(message.GetData())); + 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((uint8_t*)(message2.GetData())); + if (message2.GetTag() == (uint32_t)InternalTags::AssignID) + std::cout << id2 << std::endl; + } + } +} \ No newline at end of file