diff --git a/DEV_INFO b/DEV_INFO new file mode 100644 index 0000000..ee5e530 --- /dev/null +++ b/DEV_INFO @@ -0,0 +1,5 @@ +id -1 is server / valid message if other parameters are valid as well +id -2 is invalid network message + + +currently working on: TcpClient::SendMessage \ No newline at end of file diff --git a/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/CL.command.1.tlog b/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/CL.command.1.tlog index cf2b1b3..f06a63f 100644 Binary files a/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/CL.command.1.tlog and b/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/CL.command.1.tlog differ diff --git a/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/CL.read.1.tlog b/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/CL.read.1.tlog index 3c4f5f0..72e3d43 100644 Binary files a/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/CL.read.1.tlog and b/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/CL.read.1.tlog differ diff --git a/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/CL.write.1.tlog b/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/CL.write.1.tlog index f8ea4cf..bfd30b5 100644 Binary files a/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/CL.write.1.tlog and b/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/CL.write.1.tlog differ diff --git a/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/Lib-link.write.1.tlog b/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/Lib-link.write.1.tlog index 1670021..bd81a63 100644 Binary files a/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/Lib-link.write.1.tlog and b/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/Lib-link.write.1.tlog differ diff --git a/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/Lib.read.1.tlog b/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/Lib.read.1.tlog index 0d32cf9..d1d9bcb 100644 Binary files a/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/Lib.read.1.tlog and b/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/Lib.read.1.tlog differ diff --git a/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/lib.command.1.tlog b/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/lib.command.1.tlog index 724e276..3e3d46b 100644 Binary files a/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/lib.command.1.tlog and b/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/lib.command.1.tlog differ diff --git a/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/unsuccessfulbuild b/VoidNetVS/VoidNetVS/Release/VoidNetVS.tlog/unsuccessfulbuild deleted file mode 100644 index e69de29..0000000 diff --git a/VoidNetVS/VoidNetVS/VoidNetVS.vcxproj b/VoidNetVS/VoidNetVS/VoidNetVS.vcxproj index 1314c09..788028c 100644 --- a/VoidNetVS/VoidNetVS/VoidNetVS.vcxproj +++ b/VoidNetVS/VoidNetVS/VoidNetVS.vcxproj @@ -27,6 +27,7 @@ + @@ -41,9 +42,12 @@ + + + diff --git a/VoidNetVS/VoidNetVS/VoidNetVS.vcxproj.filters b/VoidNetVS/VoidNetVS/VoidNetVS.vcxproj.filters index 6e2ac58..11506fe 100644 --- a/VoidNetVS/VoidNetVS/VoidNetVS.vcxproj.filters +++ b/VoidNetVS/VoidNetVS/VoidNetVS.vcxproj.filters @@ -45,6 +45,9 @@ include + + include + @@ -74,8 +77,15 @@ src + + src + + + src + + \ No newline at end of file diff --git a/include/Callbacks.hpp b/include/Callbacks.hpp index bd3a456..e751357 100644 --- a/include/Callbacks.hpp +++ b/include/Callbacks.hpp @@ -8,10 +8,14 @@ #include "Defs.hpp" #include "Serializer.hpp" +/*Client Callbacks begin*/ + void OnMessage(uint16 sender, uint16 tag, uint16 subject, void *data); void OnDisconnect(uint16 id); void OnConnect(uint16 id); +/*Client Callbacks end*/ + #endif \ No newline at end of file diff --git a/include/Defs.hpp b/include/Defs.hpp index 1822fd7..0a47b54 100644 --- a/include/Defs.hpp +++ b/include/Defs.hpp @@ -185,11 +185,12 @@ enum VoidCode enum DistributionType { All, + AllAndMe, Server, Others, ID, Reply, Custom, -} +}; #endif // DEFS_HPP \ No newline at end of file diff --git a/include/NetworkMessage.hpp b/include/NetworkMessage.hpp index 0f59eb2..ca9f8d3 100644 --- a/include/NetworkMessage.hpp +++ b/include/NetworkMessage.hpp @@ -15,20 +15,22 @@ struct NetworkMessage NetworkMessage(uint16 sender, byte distribution_mode, uint16 destination_id, byte tag, uint16 subject, NetworkBuffer buffer); ~NetworkMessage(); - const NetworkMessage &EncodeMessage(); + static const NetworkBuffer &EncodeMessage(const NetworkMessage &message); const NetworkMessage &NetworkMessage::DecodeMessage(const NetworkBuffer &buffer); - const NetworkMessage &NetworkMessage::DecodeMessageHeader(const NetworkBuffer &buffer); - void *DecodeMessageData(const NetworkBuffer &buffer); - uint16 sender; - uint16 destination_id; + uint16 sender = -2; byte distribution_mode; - uint16 tag; + uint16 destination_id; + byte tag; uint16 subject; void *data; + + bool valid = false; private: + const NetworkMessage &NetworkMessage::DecodeMessageHeader(const NetworkBuffer &buffer); + void *DecodeMessageData(const NetworkBuffer &buffer); NetworkBuffer buffer; }; diff --git a/include/Serializer.hpp b/include/Serializer.hpp index 58a740a..989470d 100644 --- a/include/Serializer.hpp +++ b/include/Serializer.hpp @@ -6,11 +6,12 @@ #endif #include "Defs.hpp" +#include struct Serializer { template static const std::vector &to_bytes(const T &object); - template static const T &from_bytes(byte *bytes, T &object); + template static const T& from_bytes(byte *bytes, T& object); }; #endif \ No newline at end of file diff --git a/src/Tags.hpp b/include/Tags.hpp similarity index 78% rename from src/Tags.hpp rename to include/Tags.hpp index 154ef10..482d99d 100644 --- a/src/Tags.hpp +++ b/include/Tags.hpp @@ -5,7 +5,7 @@ #pragma once #endif -enum InternalTags : uint16 +enum InternalTags { CONNECT = 65534, DISCONNECT = 65535, diff --git a/include/TcpClient.hpp b/include/TcpClient.hpp index aff0048..1d890a8 100644 --- a/include/TcpClient.hpp +++ b/include/TcpClient.hpp @@ -3,6 +3,7 @@ #include "Defs.hpp" #include "NetworkMessage.hpp" +#include "ThreadPool.hpp" #include @@ -10,6 +11,8 @@ #pragma once #endif +#undef SendMessage + class TcpClient { public: @@ -27,21 +30,30 @@ public: NetworkBuffer ReceiveDataArray(); const NetworkMessage &ReceiveData(); - bool SendData(const NetworkMessage &message); + VoidCode SendMessage(const NetworkMessage &message); private: + static VoidCode SendNetworkMessage(const NetworkMessage &message, TcpClient *client); VoidCode Initialize(const std::string &ip, uint16 port = default_port); std::string ip; uint16 port = 0; bool initialized; + ThreadPool thread_pool; + #ifdef _MSC_VER - SOCKET socket = INVALID_SOCKET; + SOCKET tcp_socket = INVALID_SOCKET; struct addrinfo *result = nullptr; struct addrinfo *ptr = nullptr; struct addrinfo hints; #endif }; +#ifdef UNICODE +#define SendMessage SendMessageW +#else +#define SendMessage SendMessageA +#endif // !UNICODE + #endif \ No newline at end of file diff --git a/include/ThreadPool.hpp b/include/ThreadPool.hpp new file mode 100644 index 0000000..6cfc0be --- /dev/null +++ b/include/ThreadPool.hpp @@ -0,0 +1,33 @@ +#ifndef THREAD_POOL_HPP +#define THREAD_POOL_HPP + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include +#include + +class ThreadPool +{ +public: + ThreadPool(int threads); + ~ThreadPool(); + void Enqueue(std::function f); + void Shutdown(); + const ThreadPool &operator=(ThreadPool &pool); + +private: + std::vector threadPool; + std::queue> tasks; + std::mutex tasksMutex; + std::condition_variable condition; + bool terminate; + bool stopped; + void Invoke(); +}; + +#endif \ No newline at end of file diff --git a/include/VoidNetClient.hpp b/include/VoidNetClient.hpp index 7a74481..c425648 100644 --- a/include/VoidNetClient.hpp +++ b/include/VoidNetClient.hpp @@ -11,5 +11,41 @@ #include "Callbacks.hpp" #include "NetworkBuffer.hpp" #include "NetworkMessage.hpp" +#include "ThreadPool.hpp" + +#include +#include + +#undef SendMessage + +struct VoidNetClientAPI +{ + static bool Connect(const std::string &ip, uint16 port = default_port); + static void Disconnect(); + + static bool SendMessageToServer(byte tag, byte subject, void *data); + static bool SendMessageToID(uint16 id, byte tag, byte subject, void *data); + static bool SendMessageToOthers(byte tag, byte subject, void *data); + static bool SendMessageToAll(byte tag, byte subject, void *data); + static bool SendMessageToAllAndMe(byte tag, byte subject, void *data); + + static bool SendMessage(byte distribution_mode, uint16 destination_id, byte tag, byte subject, void *data); + + static void Receive(); + +private: + static void ProcessAllData(); + + static TcpClient *client; + static uint16 id; + static std::thread receive_thread; + static bool receive; +}; + +#ifdef UNICODE +#define SendMessage SendMessageW +#else +#define SendMessage SendMessageA +#endif // !UNICODE #endif diff --git a/src/NetworkMessage.cpp b/src/NetworkMessage.cpp index 6b79e2b..c81ef15 100644 --- a/src/NetworkMessage.cpp +++ b/src/NetworkMessage.cpp @@ -1,6 +1,8 @@ #include "NetworkMessage.hpp" #include "Utility.hpp" #include "Serializer.hpp" +#include "Tags.hpp" + #include NetworkMessage::NetworkMessage() @@ -12,13 +14,41 @@ NetworkMessage::NetworkMessage(uint16 sender, byte distribution_mode, uint16 des { } +NetworkMessage::NetworkMessage(const NetworkBuffer &buffer) +{ + *this = DecodeMessage(buffer); +} + NetworkMessage::~NetworkMessage() { } -const NetworkMessage &NetworkMessage::EncodeMessage() +const NetworkBuffer &NetworkMessage::EncodeMessage(const NetworkMessage &message) { - return NetworkMessage(); + NetworkBuffer buffer; + uint16 size = buffer.body_size + 1; + byte *encoded_message = new byte[size](); + buffer.body_size = size; + + byte *encoded_sender = &encoded_message[1]; + encoded_sender = Utility::BitConverter::FromUint16(message.sender); + + encoded_message[3] = message.distribution_mode; + + byte *encoded_destination_id = &encoded_message[4]; + encoded_destination_id = Utility::BitConverter::FromUint16(message.destination_id); + + encoded_message[6] = message.tag; + + byte *encoded_subject = &encoded_message[7]; + encoded_subject = Utility::BitConverter::FromUint16(message.subject); + + byte *encoded_data = &encoded_message[9]; + std::vector serialized_data = Serializer::to_bytes(message.data); + encoded_data = &serialized_data[0]; + + buffer.body = encoded_message; + return buffer; } const NetworkMessage &NetworkMessage::DecodeMessage(const NetworkBuffer &buffer) @@ -38,7 +68,7 @@ void *NetworkMessage::DecodeMessageData(const NetworkBuffer &buffer) case 0: { void *object; - return Serializer::from_bytes(buffer.body, object); + return Serializer::from_bytes(buffer.body + 9, object); } default: { @@ -50,6 +80,12 @@ void *NetworkMessage::DecodeMessageData(const NetworkBuffer &buffer) const NetworkMessage &NetworkMessage::DecodeMessageHeader(const NetworkBuffer &buffer) { - return NetworkMessage(Utility::BitConverter::ToUint16(buffer.body, 1), buffer.body[3], Utility::BitConverter::ToUint16(buffer.body, 4), - buffer.body[6], Utility::BitConverter::ToUint16(buffer.body, 7), buffer); + sender = Utility::BitConverter::ToUint16(buffer.body, 1); + distribution_mode = buffer.body[3]; + destination_id = Utility::BitConverter::ToUint16(buffer.body, 4); + tag = buffer.body[6]; + subject = Utility::BitConverter::ToUint16(buffer.body, 7); + this->buffer = buffer; + valid = sender != -2 && tag != CONNECT && tag != DISCONNECT; + return *this; } diff --git a/src/Serializer.cpp b/src/Serializer.cpp index 7a877c6..4505087 100644 --- a/src/Serializer.cpp +++ b/src/Serializer.cpp @@ -1,7 +1,5 @@ #include "Serializer.hpp" -#include - template const std::vector &Serializer::to_bytes(const T& object) { std::vector bytes; @@ -13,7 +11,7 @@ template const std::vector &Serializer::to_bytes(const T& obje return bytes; } -template T& Serializer::from_bytes(byte *bytes, T& object) +template const T& Serializer::from_bytes(byte *bytes, T& object) { static_assert(std::is_trivially_copyable::value, "not a TriviallyCopyable type"); diff --git a/src/TcpClientWindows.cpp b/src/TcpClientWindows.cpp index 7dd1b33..eb367da 100644 --- a/src/TcpClientWindows.cpp +++ b/src/TcpClientWindows.cpp @@ -7,6 +7,8 @@ #include +#undef SendMessage + VoidCode TcpClient::Initialize(const std::string &ip, uint16 port) { if (ip.size() == 0 || std::count(ip.begin(), ip.end(), '.') != 4) @@ -28,9 +30,9 @@ VoidCode TcpClient::Initialize(const std::string &ip, uint16 port) } ptr = result; - socket = ::socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); + tcp_socket = ::socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); - if (socket == INVALID_SOCKET) + if (tcp_socket == INVALID_SOCKET) { if (Config::GetUsingConsole()) std::cerr << WSAGetLastError() << std::endl; // display more info @@ -43,12 +45,12 @@ VoidCode TcpClient::Initialize(const std::string &ip, uint16 port) return VOID_SUCCESS; } -TcpClient::TcpClient() +TcpClient::TcpClient() : port(default_port), thread_pool(50) { } TcpClient::TcpClient(const std::string &ip, uint16 port) : - ip(ip), port(port) + ip(ip), port(port), thread_pool(50) { } @@ -92,7 +94,7 @@ VoidCode TcpClient::Connect() if (code != VOID_SUCCESS) return code; } - uint16 connect_code = ::connect(socket, ptr->ai_addr, ptr->ai_addrlen); + uint16 connect_code = ::connect(tcp_socket, ptr->ai_addr, ptr->ai_addrlen); if (connect_code == SOCKET_ERROR) return VOID_COULDNT_CONNECT; } @@ -101,16 +103,19 @@ NetworkBuffer TcpClient::ReceiveDataArray() { NetworkBuffer buffer; - if (recv(socket, reinterpret_cast(buffer.body_size), 4, 0) != 4 || WSAGetLastError() != 0) + int32 header_received = recv(tcp_socket, reinterpret_cast(buffer.body_size), 4, 0); + + if (header_received != 4 || WSAGetLastError() != 0) // this header is completely unrelated to the network message header - this header is the body size of the network message { - // there was a problem receiving the body size of the message + // there was a problem receiving the body size of the message or theres no header to receive return NetworkBuffer(); } buffer.body = new byte[buffer.body_size](); - if (recv(socket, reinterpret_cast(buffer.body), buffer.body_size, 0) != buffer.body_size || WSAGetLastError() != 0) + int32 body_received = recv(tcp_socket, reinterpret_cast(buffer.body), buffer.body_size, 0); + if (body_received != buffer.body_size || WSAGetLastError() != 0) { - //there was a problem receiving the body of the message + //there was a problem receiving the body of the message or theres no body to receive return NetworkBuffer(); } @@ -119,8 +124,7 @@ NetworkBuffer TcpClient::ReceiveDataArray() const NetworkMessage &TcpClient::ReceiveData() { - NetworkBuffer received_data = ReceiveDataArray(); - NetworkMessage message = NetworkMessage(received_data); + NetworkMessage message(ReceiveDataArray()); if (message.tag == CONNECT) OnConnect(message.sender); else if (message.tag == DISCONNECT) @@ -130,7 +134,16 @@ const NetworkMessage &TcpClient::ReceiveData() return message; } -bool TcpClient::SendData(const NetworkMessage &message) +VoidCode TcpClient::SendNetworkMessage(const NetworkMessage &message, TcpClient *client) { - return false; + NetworkBuffer buffer = message.EncodeMessage(message); + int32 sent_bytes = send(client->tcp_socket, reinterpret_cast(buffer.body), buffer.body_size, 0); } + +VoidCode TcpClient::SendMessage(const NetworkMessage &message) +{ + thread_pool.Enqueue([]() + { + //SendNetworkMessage(message, this); + }); +} \ No newline at end of file diff --git a/src/ThreadPool.cpp b/src/ThreadPool.cpp new file mode 100644 index 0000000..3d59a85 --- /dev/null +++ b/src/ThreadPool.cpp @@ -0,0 +1,57 @@ +#include "ThreadPool.hpp" + +ThreadPool::ThreadPool(int threads) : + terminate(false), + stopped(false) +{ + for (int i = 0; i < threads; i++) + threadPool.emplace_back(std::thread(&ThreadPool::Invoke, this)); +} + +void ThreadPool::Enqueue(std::function f) +{ + std::unique_lock lock(tasksMutex); + tasks.push(f); + condition.notify_one(); +} + +void ThreadPool::Invoke() { + + std::function task; + while (true) + { + std::unique_lock lock(tasksMutex); + condition.wait(lock, [this] { return !tasks.empty() || terminate; }); + if (terminate && tasks.empty()) + { + return; + } + task = tasks.front(); + tasks.pop(); + task(); + } +} + +void ThreadPool::Shutdown() +{ + std::unique_lock lock(tasksMutex); + terminate = true; + condition.notify_all(); + + for (std::thread &thread : threadPool) + thread.join(); + + threadPool.empty(); + stopped = true; +} + +const ThreadPool &ThreadPool::operator=(ThreadPool &pool) +{ + return pool; +} + +ThreadPool::~ThreadPool() +{ + if (!stopped) + Shutdown(); +} \ No newline at end of file diff --git a/src/VoidNetClient.cpp b/src/VoidNetClient.cpp new file mode 100644 index 0000000..9ddc1f0 --- /dev/null +++ b/src/VoidNetClient.cpp @@ -0,0 +1,79 @@ +#include "VoidNetClient.hpp" +#include "Utility.hpp" +#include "Tags.hpp" + +#undef SendMessage + +bool VoidNetClientAPI::Connect(const std::string &ip, uint16 port) +{ + client->SetIP(ip); + client->SetPort(port); + return client->Connect() == VOID_SUCCESS; +} + +bool VoidNetClientAPI::SendMessageToServer(byte tag, byte subject, void *data) +{ + return SendMessage(Server, 0, tag, subject, data); +} + +bool VoidNetClientAPI::SendMessageToID(uint16 destination_id, byte tag, byte subject, void *data) +{ + return SendMessage(ID, destination_id, tag, subject, data); +} + +bool VoidNetClientAPI::SendMessageToOthers(byte tag, byte subject, void *data) +{ + return SendMessage(Others, 0, tag, subject, data); +} + +bool VoidNetClientAPI::SendMessageToAll(byte tag, byte subject, void *data) +{ + return SendMessage(All, 0, tag, subject, data); +} + +bool VoidNetClientAPI::SendMessageToAllAndMe(byte tag, byte subject, void *data) +{ + return SendMessage(AllAndMe, 0, tag, subject, data); +} + +bool VoidNetClientAPI::SendMessage(byte distribution_mode, uint16 destination_id, byte tag, byte subject, void *data) +{ + NetworkMessage message; + message.tag = tag; + message.subject = subject; + message.data = data; + message.distribution_mode = distribution_mode; + message.sender = id; + message.destination_id = destination_id; + return client->SendMessage(message) == VOID_SUCCESS; +} + +void VoidNetClientAPI::Receive() +{ + receive_thread = std::thread(ProcessAllData); + receive_thread.detach(); +} + +void VoidNetClientAPI::ProcessAllData() +{ + while (receive) + { + NetworkMessage message = client->ReceiveDataArray(); + if (message.valid) + { + if (message.tag == CONNECT) + OnConnect(message.sender); + else if (message.tag == DISCONNECT) + OnDisconnect(message.sender); + else + OnMessage(message.sender, message.tag, message.subject, message.data); + } + } +} + +void VoidNetClientAPI::Disconnect() +{ + Utility::Delete(client); + receive = false; + receive_thread.join(); +}