From 37015e4f3b42de4f1b7dbccf9fbb7c838e0b2e73 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 13 Oct 2024 21:21:36 +0200 Subject: [PATCH] add new header implementation for game<->launcher communication --- include/Utils.h | 50 ++++++++++++++++++++++++- src/Network/Core.cpp | 53 +++++++-------------------- src/Network/GlobalHandler.cpp | 69 ++++++++--------------------------- 3 files changed, 78 insertions(+), 94 deletions(-) diff --git a/include/Utils.h b/include/Utils.h index 0342c11..f12f22a 100644 --- a/include/Utils.h +++ b/include/Utils.h @@ -1,6 +1,19 @@ #pragma once +#include +#include #include #include +#include +#include +#include +#include +#if defined(__linux__) +#include +#include "linuxfixes.h" +#else +#include +#include +#endif namespace Utils { inline std::vector Split(const std::string& String, const std::string& delimiter) { @@ -17,4 +30,39 @@ namespace Utils { Val.push_back(s); return Val; }; -}; \ No newline at end of file + + template + inline std::vector PrependHeader(const T& data) { + std::vector size_buffer(4); + uint32_t len = data.size(); + std::memcpy(size_buffer.data(), &len, 4); + std::vector buffer; + buffer.reserve(size_buffer.size() + data.size()); + buffer.insert(buffer.begin(), size_buffer.begin(), size_buffer.end()); + buffer.insert(buffer.end(), data.begin(), data.end()); + return buffer; + } + + inline uint32_t RecvHeader(SOCKET socket) { + std::array header_buffer {}; + auto n = recv(socket, reinterpret_cast(header_buffer.data()), header_buffer.size(), MSG_WAITALL); + if (n < 0) { + throw std::runtime_error(std::string("recv() of header failed: ") + std::strerror(errno)); + } else if (n == 0) { + throw std::runtime_error("Game disconnected"); + } + return *reinterpret_cast(header_buffer.data()); + } + + /// Throws!!! + inline void ReceiveFromGame(SOCKET socket, std::vector& out_data) { + auto header = RecvHeader(socket); + out_data.resize(header); + auto n = recv(socket, reinterpret_cast(out_data.data()), out_data.size(), MSG_WAITALL); + if (n < 0) { + throw std::runtime_error(std::string("recv() of data failed: ") + std::strerror(errno)); + } else if (n == 0) { + throw std::runtime_error("Game disconnected"); + } + } +}; diff --git a/src/Network/Core.cpp b/src/Network/Core.cpp index 1593e50..cec00ed 100644 --- a/src/Network/Core.cpp +++ b/src/Network/Core.cpp @@ -8,6 +8,7 @@ #include "Http.h" #include "Network/network.hpp" #include "Security/Init.h" +#include "Utils.h" #include #include #if defined(_WIN32) @@ -89,7 +90,8 @@ void StartSync(const std::string& Data) { void CoreSend(std::string data) { if (CoreSocket != -1) { - int res = send(CoreSocket, (data + "\n").c_str(), int(data.size()) + 1, 0); + auto ToSend = Utils::PrependHeader(data); + int res = send(CoreSocket, ToSend.data(), ToSend.size(), MSG_WAITALL); if (res < 0) { debug("(Core) send failed with error: " + std::to_string(WSAGetLastError())); } @@ -165,7 +167,7 @@ void Parse(std::string Data, SOCKET CSocket) { Ping = "-2"; else Ping = std::to_string(ping); - Data = std::string(UlStatus) + "\n" + "Up" + Ping; + Data = "Up" + Ping; } break; case 'M': @@ -227,7 +229,8 @@ void Parse(std::string Data, SOCKET CSocket) { break; } if (!Data.empty() && CSocket != -1) { - int res = send(CSocket, (Data + "\n").c_str(), int(Data.size()) + 1, 0); + auto ToSend = Utils::PrependHeader(Data); + int res = send(CSocket, ToSend.data(), ToSend.size(), MSG_WAITALL); if (res < 0) { debug("(Core) send failed with error: " + std::to_string(WSAGetLastError())); } @@ -235,45 +238,17 @@ void Parse(std::string Data, SOCKET CSocket) { } void GameHandler(SOCKET Client) { CoreSocket = Client; - int32_t Size, Temp, Rcv; - char Header[10] = { 0 }; + std::vector data{}; do { - Rcv = 0; - do { - Temp = recv(Client, &Header[Rcv], 1, 0); - if (Temp < 1) - break; - if (!isdigit(Header[Rcv]) && Header[Rcv] != '>') { - error("(Core) Invalid lua communication"); - KillSocket(Client); - return; - } - } while (Header[Rcv++] != '>'); - if (Temp < 1) - break; - if (std::from_chars(Header, &Header[Rcv], Size).ptr[0] != '>') { - debug("(Core) Invalid lua Header -> " + std::string(Header, Rcv)); + try { + Utils::ReceiveFromGame(Client, data); + Parse(std::string(data.data(), data.size()), Client); + } catch (const std::exception& e) { + error(std::string("Error while receiving from game on core: ") + e.what()); break; } - std::string Ret(Size, 0); - Rcv = 0; - - do { - Temp = recv(Client, &Ret[Rcv], Size - Rcv, 0); - if (Temp < 1) - break; - Rcv += Temp; - } while (Rcv < Size); - if (Temp < 1) - break; - - Parse(Ret, Client); - } while (Temp > 0); - if (Temp == 0) { - debug("(Core) Connection closing"); - } else { - debug("(Core) recv failed with error: " + std::to_string(WSAGetLastError())); - } + } while (true); + debug("(Core) Connection closing"); NetReset(); KillSocket(Client); } diff --git a/src/Network/GlobalHandler.cpp b/src/Network/GlobalHandler.cpp index cde0684..bcf5abe 100644 --- a/src/Network/GlobalHandler.cpp +++ b/src/Network/GlobalHandler.cpp @@ -6,6 +6,7 @@ /// Created by Anonymous275 on 7/25/2020 /// #include "Network/network.hpp" +#include "Utils.h" #include #include #if defined(_WIN32) @@ -22,11 +23,11 @@ #endif #include "Logger.h" +#include "Options.h" #include #include #include #include -#include "Options.h" std::chrono::time_point PingStart, PingEnd; bool GConnected = false; @@ -61,30 +62,13 @@ bool CheckBytes(uint32_t Bytes) { void GameSend(std::string_view Data) { static std::mutex Lock; std::scoped_lock Guard(Lock); - if (TCPTerminate || !GConnected || CSocket == -1) - return; - int32_t Size, Temp, Sent; - Size = int32_t(Data.size()); - Sent = 0; -#ifdef DEBUG - if (Size > 1000) { - debug("Launcher -> game (" + std::to_string(Size) + ")"); - } -#endif - do { - if (Sent > -1) { - Temp = send(CSocket, &Data[Sent], Size - Sent, 0); - } - if (!CheckBytes(Temp)) - return; - Sent += Temp; - } while (Sent < Size); - // send separately to avoid an allocation for += "\n" - Temp = send(CSocket, "\n", 1, 0); - if (!CheckBytes(Temp)) { - return; + auto ToSend = Utils::PrependHeader(Data); + auto Result = send(CSocket, ToSend.data(), ToSend.size(), MSG_WAITALL); + if (Result < 0) { + error("(Game) send failed with error: " + std::to_string(WSAGetLastError())); } } + void ServerSend(std::string Data, bool Rel) { if (Terminate || Data.empty()) return; @@ -262,42 +246,19 @@ void TCPGameServer(const std::string& IP, int Port) { NetMainThread = std::make_unique(NetMain, IP, Port); CServer = false; } - int32_t Size, Temp, Rcv; - char Header[10] = { 0 }; + std::vector data {}; // Read byte by byte until '>' is rcved then get the size and read based on it do { - Rcv = 0; - - do { - Temp = recv(CSocket, &Header[Rcv], 1, 0); - if (Temp < 1 || TCPTerminate) - break; - } while (Header[Rcv++] != '>'); - if (Temp < 1 || TCPTerminate) - break; - if (std::from_chars(Header, &Header[Rcv], Size).ptr[0] != '>') { - debug("(Game) Invalid lua Header -> " + std::string(Header, Rcv)); + try { + Utils::ReceiveFromGame(CSocket, data); + ServerSend(std::string(data.data(), data.size()), false); + } catch (const std::exception& e) { + error(std::string("Error while receiving from game on proxy: ") + e.what()); break; } - std::string Ret(Size, 0); - Rcv = 0; - do { - Temp = recv(CSocket, &Ret[Rcv], Size - Rcv, 0); - if (Temp < 1) - break; - Rcv += Temp; - } while (Rcv < Size && !TCPTerminate); - if (Temp < 1 || TCPTerminate) - break; - - ServerSend(Ret, false); - - } while (Temp > 0 && !TCPTerminate); - if (Temp == 0) - debug("(Proxy) Connection closing"); - else - debug("(Proxy) recv failed error : " + std::to_string(WSAGetLastError())); + } while (!TCPTerminate); + debug("(Proxy) Connection closing"); } TCPTerminate = true; GConnected = false;