diff --git a/include/Utils.h b/include/Utils.h index b7def4a..89b7f5d 100644 --- a/include/Utils.h +++ b/include/Utils.h @@ -13,9 +13,22 @@ #include #include #include +#include +#include #include #include #include +#include +#include +#include +#include +#if defined(__linux__) +#include +#include "linuxfixes.h" +#else +#include +#include +#endif #ifdef _WIN32 #define beammp_fs_string std::wstring @@ -286,4 +299,40 @@ namespace Utils { return ""; } } -}; \ 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 902e1c7..6982ef0 100644 --- a/src/Network/Core.cpp +++ b/src/Network/Core.cpp @@ -7,6 +7,7 @@ #include "Http.h" #include "Network/network.hpp" #include "Security/Init.h" +#include "Utils.h" #include #include #if defined(_WIN32) @@ -188,7 +189,8 @@ void CoreSend(std::string data) { std::lock_guard lock(sendMutex); 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())); } @@ -278,7 +280,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': @@ -348,51 +350,29 @@ void Parse(std::string Data, SOCKET CSocket) { Data.clear(); break; } - if (!Data.empty()) - CoreSend(Data); + if (!Data.empty() && CSocket != -1) { + 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())); + } + } } void GameHandler(SOCKET Client) { CoreSocket = Client; - int32_t Size, Rcv; + std::vector data{}; int Temp; char Header[10] = { 0 }; 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 776169e..cf2d9dd 100644 --- a/src/Network/GlobalHandler.cpp +++ b/src/Network/GlobalHandler.cpp @@ -5,6 +5,7 @@ */ #include "Network/network.hpp" +#include "Utils.h" #include #include #if defined(_WIN32) @@ -21,6 +22,7 @@ #endif #include "Logger.h" +#include "Options.h" #include #include #include @@ -62,30 +64,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; @@ -268,40 +253,19 @@ void TCPGameServer(const std::string& IP, int Port) { int32_t Size, Rcv; int Temp; 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;