mirror of
https://github.com/BeamMP/BeamMP-Launcher.git
synced 2026-10-26 14:10:08 +00:00
Better header (redone) (#139)
This commit is contained in:
5 files changed
+116
-112
No files matched your search
+51
-1
@@ -13,9 +13,22 @@
|
|||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <vector>
|
#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
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define beammp_fs_string std::wstring
|
#define beammp_fs_string std::wstring
|
||||||
@@ -31,6 +44,8 @@
|
|||||||
#define beammp_stdout std::cout
|
#define beammp_stdout std::cout
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "Logger.h"
|
||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
inline std::vector<std::string> Split(const std::string& String, const std::string& delimiter) {
|
inline std::vector<std::string> Split(const std::string& String, const std::string& delimiter) {
|
||||||
std::vector<std::string> Val;
|
std::vector<std::string> Val;
|
||||||
@@ -45,7 +60,7 @@ namespace Utils {
|
|||||||
if (!s.empty())
|
if (!s.empty())
|
||||||
Val.push_back(s);
|
Val.push_back(s);
|
||||||
return Val;
|
return Val;
|
||||||
};
|
}
|
||||||
inline std::string ExpandEnvVars(const std::string& input) {
|
inline std::string ExpandEnvVars(const std::string& input) {
|
||||||
std::string result;
|
std::string result;
|
||||||
std::regex envPattern(R"(%([^%]+)%|\$([A-Za-z_][A-Za-z0-9_]*)|\$\{([^}]+)\})");
|
std::regex envPattern(R"(%([^%]+)%|\$([A-Za-z_][A-Za-z0-9_]*)|\$\{([^}]+)\})");
|
||||||
@@ -286,4 +301,39 @@ namespace Utils {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
+30
-19
@@ -4,6 +4,8 @@
|
|||||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include "Utils.h"
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
@@ -18,7 +20,6 @@
|
|||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "Options.h"
|
#include "Options.h"
|
||||||
#include "Startup.h"
|
#include "Startup.h"
|
||||||
#include "Utils.h"
|
|
||||||
#include <Security/Init.h>
|
#include <Security/Init.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@@ -57,12 +58,11 @@ std::filesystem::path GetGamePath() {
|
|||||||
if (ini.contains("filesystem") && std::get<std::map<std::string, std::string>>(ini["filesystem"]).contains("UserPath"))
|
if (ini.contains("filesystem") && std::get<std::map<std::string, std::string>>(ini["filesystem"]).contains("UserPath"))
|
||||||
userPath = Utils::ToWString(std::get<std::map<std::string, std::string>>(ini["filesystem"])["UserPath"]);
|
userPath = Utils::ToWString(std::get<std::map<std::string, std::string>>(ini["filesystem"])["UserPath"]);
|
||||||
|
|
||||||
if (!userPath.empty() && Path.empty())
|
if (userPath = Utils::ExpandEnvVars(userPath); std::filesystem::exists(userPath)) {
|
||||||
if (userPath = Utils::ExpandEnvVars(userPath); std::filesystem::exists(userPath)) {
|
Path = userPath;
|
||||||
Path = userPath;
|
debug(L"Using custom user folder path from startup.ini: " + Path.wstring());
|
||||||
debug(L"Using custom user folder path from startup.ini: " + Path.wstring());
|
} else
|
||||||
} else
|
warn(L"Found custom user folder path (" + userPath + L") in startup.ini but it doesn't exist, skipping");
|
||||||
warn(L"Found custom user folder path (" + userPath + L") in startup.ini but it doesn't exist, skipping");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Path.empty()) {
|
if (Path.empty()) {
|
||||||
@@ -94,12 +94,11 @@ std::filesystem::path GetGamePath() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userPath.empty() && Path.empty())
|
if (userPath = std::filesystem::path(Utils::ExpandEnvVars(userPath)); std::filesystem::exists(userPath)) {
|
||||||
if (userPath = std::filesystem::path(Utils::ExpandEnvVars(userPath)); std::filesystem::exists(userPath)) {
|
Path = userPath;
|
||||||
Path = userPath;
|
debug(L"Using custom user folder path from BeamNG.Drive.ini: " + Path.wstring());
|
||||||
debug(L"Using custom user folder path from BeamNG.Drive.ini: " + Path.wstring());
|
} else
|
||||||
} else
|
warn(L"Found custom user folder path (" + userPath + L") in BeamNG.Drive.ini but it doesn't exist, skipping");
|
||||||
warn(L"Found custom user folder path (" + userPath + L") in BeamNG.Drive.ini but it doesn't exist, skipping");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +174,6 @@ void StartGame(std::wstring Dir) {
|
|||||||
}
|
}
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
void StartGame(std::string Dir) {
|
void StartGame(std::string Dir) {
|
||||||
int status;
|
|
||||||
std::string filename = (Dir + "/BinLinux/BeamNG.drive.x64");
|
std::string filename = (Dir + "/BinLinux/BeamNG.drive.x64");
|
||||||
std::vector<const char*> argv;
|
std::vector<const char*> argv;
|
||||||
argv.push_back(filename.data());
|
argv.push_back(filename.data());
|
||||||
@@ -185,11 +183,24 @@ void StartGame(std::string Dir) {
|
|||||||
|
|
||||||
argv.push_back(nullptr);
|
argv.push_back(nullptr);
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
posix_spawn_file_actions_t spawn_actions;
|
|
||||||
posix_spawn_file_actions_init(&spawn_actions);
|
posix_spawn_file_actions_t file_actions;
|
||||||
posix_spawn_file_actions_addclose(&spawn_actions, STDOUT_FILENO);
|
auto status = posix_spawn_file_actions_init(&file_actions);
|
||||||
posix_spawn_file_actions_addclose(&spawn_actions, STDERR_FILENO);
|
// disable stdout
|
||||||
int result = posix_spawn(&pid, filename.c_str(), &spawn_actions, nullptr, const_cast<char**>(argv.data()), environ);
|
if (status != 0) {
|
||||||
|
error(std::string("posix_spawn_file_actions_init failed: ") + std::strerror(errno));
|
||||||
|
}
|
||||||
|
status = posix_spawn_file_actions_addclose(&file_actions, STDOUT_FILENO);
|
||||||
|
if (status != 0) {
|
||||||
|
error(std::string("posix_spawn_file_actions_addclose for STDOUT failed: ") + std::strerror(errno));
|
||||||
|
}
|
||||||
|
status = posix_spawn_file_actions_addclose(&file_actions, STDERR_FILENO);
|
||||||
|
if (status != 0) {
|
||||||
|
error(std::string("posix_spawn_file_actions_addclose for STDERR failed: ") + std::strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
// launch the game
|
||||||
|
int result = posix_spawn(&pid, filename.c_str(), &file_actions, NULL, const_cast<char**>(argv.data()), environ);
|
||||||
|
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
error("Failed to Launch the game! launcher closing soon");
|
error("Failed to Launch the game! launcher closing soon");
|
||||||
|
|||||||
+19
-39
@@ -7,6 +7,7 @@
|
|||||||
#include "Http.h"
|
#include "Http.h"
|
||||||
#include "Network/network.hpp"
|
#include "Network/network.hpp"
|
||||||
#include "Security/Init.h"
|
#include "Security/Init.h"
|
||||||
|
#include "Utils.h"
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
@@ -188,7 +189,8 @@ void CoreSend(std::string data) {
|
|||||||
std::lock_guard lock(sendMutex);
|
std::lock_guard lock(sendMutex);
|
||||||
|
|
||||||
if (CoreSocket != -1) {
|
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(), 0);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
debug("(Core) send failed with error: " + std::to_string(WSAGetLastError()));
|
debug("(Core) send failed with error: " + std::to_string(WSAGetLastError()));
|
||||||
}
|
}
|
||||||
@@ -278,7 +280,7 @@ void Parse(std::string Data, SOCKET CSocket) {
|
|||||||
Ping = "-2";
|
Ping = "-2";
|
||||||
else
|
else
|
||||||
Ping = std::to_string(ping);
|
Ping = std::to_string(ping);
|
||||||
Data = std::string(UlStatus) + "\n" + "Up" + Ping;
|
Data = "Up" + Ping;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'M':
|
case 'M':
|
||||||
@@ -348,51 +350,29 @@ void Parse(std::string Data, SOCKET CSocket) {
|
|||||||
Data.clear();
|
Data.clear();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!Data.empty())
|
if (!Data.empty() && CSocket != -1) {
|
||||||
CoreSend(Data);
|
auto ToSend = Utils::PrependHeader(Data);
|
||||||
|
int res = send(CSocket, ToSend.data(), ToSend.size(), 0);
|
||||||
|
if (res < 0) {
|
||||||
|
debug("(Core) send failed with error: " + std::to_string(WSAGetLastError()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void GameHandler(SOCKET Client) {
|
void GameHandler(SOCKET Client) {
|
||||||
CoreSocket = Client;
|
CoreSocket = Client;
|
||||||
int32_t Size, Rcv;
|
std::vector<char> data{};
|
||||||
int Temp;
|
int Temp;
|
||||||
char Header[10] = { 0 };
|
char Header[10] = { 0 };
|
||||||
do {
|
do {
|
||||||
Rcv = 0;
|
try {
|
||||||
do {
|
Utils::ReceiveFromGame(Client, data);
|
||||||
Temp = recv(Client, &Header[Rcv], 1, 0);
|
Parse(std::string(data.data(), data.size()), Client);
|
||||||
if (Temp < 1)
|
} catch (const std::exception& e) {
|
||||||
break;
|
error(std::string("Error while receiving from game on core: ") + e.what());
|
||||||
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));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
std::string Ret(Size, 0);
|
} while (true);
|
||||||
Rcv = 0;
|
debug("(Core) Connection closing");
|
||||||
|
|
||||||
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()));
|
|
||||||
}
|
|
||||||
NetReset();
|
NetReset();
|
||||||
KillSocket(Client);
|
KillSocket(Client);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Network/network.hpp"
|
#include "Network/network.hpp"
|
||||||
|
#include "Utils.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
@@ -21,6 +22,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
|
#include "Options.h"
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -62,30 +64,13 @@ bool CheckBytes(uint32_t Bytes) {
|
|||||||
void GameSend(std::string_view Data) {
|
void GameSend(std::string_view Data) {
|
||||||
static std::mutex Lock;
|
static std::mutex Lock;
|
||||||
std::scoped_lock Guard(Lock);
|
std::scoped_lock Guard(Lock);
|
||||||
if (TCPTerminate || !GConnected || CSocket == -1)
|
auto ToSend = Utils::PrependHeader<std::string_view>(Data);
|
||||||
return;
|
auto Result = send(CSocket, ToSend.data(), ToSend.size(), 0);
|
||||||
int32_t Size, Temp, Sent;
|
if (Result < 0) {
|
||||||
Size = int32_t(Data.size());
|
error("(Game) send failed with error: " + std::to_string(WSAGetLastError()));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerSend(std::string Data, bool Rel) {
|
void ServerSend(std::string Data, bool Rel) {
|
||||||
if (Terminate || Data.empty())
|
if (Terminate || Data.empty())
|
||||||
return;
|
return;
|
||||||
@@ -268,40 +253,19 @@ void TCPGameServer(const std::string& IP, int Port) {
|
|||||||
int32_t Size, Rcv;
|
int32_t Size, Rcv;
|
||||||
int Temp;
|
int Temp;
|
||||||
char Header[10] = { 0 };
|
char Header[10] = { 0 };
|
||||||
|
std::vector<char> data {};
|
||||||
|
|
||||||
// Read byte by byte until '>' is rcved then get the size and read based on it
|
// Read byte by byte until '>' is rcved then get the size and read based on it
|
||||||
do {
|
do {
|
||||||
Rcv = 0;
|
try {
|
||||||
|
Utils::ReceiveFromGame(CSocket, data);
|
||||||
do {
|
ServerSend(std::string(data.data(), data.size()), false);
|
||||||
Temp = recv(CSocket, &Header[Rcv], 1, 0);
|
} catch (const std::exception& e) {
|
||||||
if (Temp < 1 || TCPTerminate)
|
error(std::string("Error while receiving from game on proxy: ") + e.what());
|
||||||
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));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
std::string Ret(Size, 0);
|
} while (!TCPTerminate);
|
||||||
Rcv = 0;
|
debug("(Proxy) Connection closing");
|
||||||
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()));
|
|
||||||
}
|
}
|
||||||
TCPTerminate = true;
|
TCPTerminate = true;
|
||||||
GConnected = false;
|
GConnected = false;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include "Utils.h"
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#include <shlobj_core.h>
|
#include <shlobj_core.h>
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
@@ -15,8 +16,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#endif
|
#endif
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "Utils.h"
|
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|||||||
Reference in new issue
Block a user