Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 52 additions & 2 deletions include/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,22 @@
#include <openssl/err.h>
#include <openssl/evp.h>
#include <regex>
#include <cstdint>
#include <cstring>
#include <string>
#include <variant>
#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
#define beammp_fs_string std::wstring
Expand All @@ -31,6 +44,8 @@
#define beammp_stdout std::cout
#endif

#include "Logger.h"

namespace Utils {
inline std::vector<std::string> Split(const std::string& String, const std::string& delimiter) {
std::vector<std::string> Val;
Expand All @@ -45,7 +60,7 @@ namespace Utils {
if (!s.empty())
Val.push_back(s);
return Val;
};
}
inline std::string ExpandEnvVars(const std::string& input) {
std::string result;
std::regex envPattern(R"(%([^%]+)%|\$([A-Za-z_][A-Za-z0-9_]*)|\$\{([^}]+)\})");
Expand Down Expand Up @@ -286,4 +301,39 @@ namespace Utils {
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");
}
}
};
49 changes: 30 additions & 19 deletions src/GameStart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
SPDX-License-Identifier: AGPL-3.0-or-later
*/

#include <cstring>
#include "Utils.h"
#if defined(_WIN32)
#include <shlobj.h>
#elif defined(__linux__)
Expand All @@ -18,7 +20,6 @@
#include "Logger.h"
#include "Options.h"
#include "Startup.h"
#include "Utils.h"
#include <Security/Init.h>
#include <filesystem>
#include <thread>
Expand Down Expand Up @@ -57,12 +58,11 @@ std::filesystem::path GetGamePath() {
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"]);

if (!userPath.empty() && Path.empty())
if (userPath = Utils::ExpandEnvVars(userPath); std::filesystem::exists(userPath)) {
Path = userPath;
debug(L"Using custom user folder path from startup.ini: " + Path.wstring());
} else
warn(L"Found custom user folder path (" + userPath + L") in startup.ini but it doesn't exist, skipping");
if (userPath = Utils::ExpandEnvVars(userPath); std::filesystem::exists(userPath)) {
Path = userPath;
debug(L"Using custom user folder path from startup.ini: " + Path.wstring());
} else
warn(L"Found custom user folder path (" + userPath + L") in startup.ini but it doesn't exist, skipping");
}

if (Path.empty()) {
Expand Down Expand Up @@ -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)) {
Path = userPath;
debug(L"Using custom user folder path from BeamNG.Drive.ini: " + Path.wstring());
} else
warn(L"Found custom user folder path (" + userPath + L") in BeamNG.Drive.ini but it doesn't exist, skipping");
if (userPath = std::filesystem::path(Utils::ExpandEnvVars(userPath)); std::filesystem::exists(userPath)) {
Path = userPath;
debug(L"Using custom user folder path from BeamNG.Drive.ini: " + Path.wstring());
} else
warn(L"Found custom user folder path (" + userPath + L") in BeamNG.Drive.ini but it doesn't exist, skipping");
}
}

Expand Down Expand Up @@ -175,7 +174,6 @@ void StartGame(std::wstring Dir) {
}
#elif defined(__linux__)
void StartGame(std::string Dir) {
int status;
std::string filename = (Dir + "/BinLinux/BeamNG.drive.x64");
std::vector<const char*> argv;
argv.push_back(filename.data());
Expand All @@ -185,11 +183,24 @@ void StartGame(std::string Dir) {

argv.push_back(nullptr);
pid_t pid;
posix_spawn_file_actions_t spawn_actions;
posix_spawn_file_actions_init(&spawn_actions);
posix_spawn_file_actions_addclose(&spawn_actions, STDOUT_FILENO);
posix_spawn_file_actions_addclose(&spawn_actions, STDERR_FILENO);
int result = posix_spawn(&pid, filename.c_str(), &spawn_actions, nullptr, const_cast<char**>(argv.data()), environ);

posix_spawn_file_actions_t file_actions;
auto status = posix_spawn_file_actions_init(&file_actions);
// disable stdout
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) {
error("Failed to Launch the game! launcher closing soon");
Expand Down
58 changes: 19 additions & 39 deletions src/Network/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "Http.h"
#include "Network/network.hpp"
#include "Security/Init.h"
#include "Utils.h"
#include <cstdlib>
#include <regex>
#if defined(_WIN32)
Expand Down Expand Up @@ -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(), 0);
if (res < 0) {
debug("(Core) send failed with error: " + std::to_string(WSAGetLastError()));
}
Expand Down Expand Up @@ -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':
Expand Down Expand Up @@ -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(), 0);
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<char> 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);
}
Expand Down
66 changes: 15 additions & 51 deletions src/Network/GlobalHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

#include "Network/network.hpp"
#include "Utils.h"
#include <memory>
#include <zlib.h>
#if defined(_WIN32)
Expand All @@ -21,6 +22,7 @@
#endif

#include "Logger.h"
#include "Options.h"
#include <charconv>
#include <mutex>
#include <string>
Expand Down Expand Up @@ -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<std::string_view>(Data);
auto Result = send(CSocket, ToSend.data(), ToSend.size(), 0);
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;
Expand Down Expand Up @@ -268,40 +253,19 @@ void TCPGameServer(const std::string& IP, int Port) {
int32_t Size, Rcv;
int Temp;
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;
Expand Down
3 changes: 1 addition & 2 deletions src/Security/BeamNG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@


#include <filesystem>
#include "Utils.h"
#if defined(_WIN32)
#include <shlobj_core.h>
#elif defined(__linux__)
Expand All @@ -15,8 +16,6 @@
#include <vector>
#endif
#include "Logger.h"
#include "Utils.h"

#include <fstream>
#include <string>
#include <thread>
Expand Down
Loading