mirror of
https://github.com/BeamMP/BeamMP-Launcher.git
synced 2025-07-01 15:36:10 +00:00
add new header implementation for game<->launcher communication
This commit is contained in:
parent
de9d6ffc85
commit
37015e4f3b
@ -1,6 +1,19 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#if defined(__linux__)
|
||||
#include <sys/socket.h>
|
||||
#include "linuxfixes.h"
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
namespace Utils {
|
||||
inline std::vector<std::string> Split(const std::string& String, const std::string& delimiter) {
|
||||
@ -17,4 +30,39 @@ namespace Utils {
|
||||
Val.push_back(s);
|
||||
return Val;
|
||||
};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline std::vector<char> PrependHeader(const T& data) {
|
||||
std::vector<char> size_buffer(4);
|
||||
uint32_t len = data.size();
|
||||
std::memcpy(size_buffer.data(), &len, 4);
|
||||
std::vector<char> 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<uint8_t, sizeof(uint32_t)> header_buffer {};
|
||||
auto n = recv(socket, reinterpret_cast<char*>(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<uint32_t*>(header_buffer.data());
|
||||
}
|
||||
|
||||
/// Throws!!!
|
||||
inline void ReceiveFromGame(SOCKET socket, std::vector<char>& out_data) {
|
||||
auto header = RecvHeader(socket);
|
||||
out_data.resize(header);
|
||||
auto n = recv(socket, reinterpret_cast<char*>(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");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "Http.h"
|
||||
#include "Network/network.hpp"
|
||||
#include "Security/Init.h"
|
||||
#include "Utils.h"
|
||||
#include <cstdlib>
|
||||
#include <regex>
|
||||
#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<char> 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);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
/// Created by Anonymous275 on 7/25/2020
|
||||
///
|
||||
#include "Network/network.hpp"
|
||||
#include "Utils.h"
|
||||
#include <memory>
|
||||
#include <zlib.h>
|
||||
#if defined(_WIN32)
|
||||
@ -22,11 +23,11 @@
|
||||
#endif
|
||||
|
||||
#include "Logger.h"
|
||||
#include "Options.h"
|
||||
#include <charconv>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include "Options.h"
|
||||
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> 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<std::string_view>(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<std::thread>(NetMain, IP, Port);
|
||||
CServer = false;
|
||||
}
|
||||
int32_t Size, Temp, Rcv;
|
||||
char Header[10] = { 0 };
|
||||
std::vector<char> 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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user