32 Commits

Author SHA1 Message Date
Tixx
4f03d21dea Move mod caching directory log 2024-11-14 11:12:19 +01:00
Lion
00bd5be4d0 add PR template 2024-11-13 16:20:54 +01:00
Tixx
dff2f2712b Bump version 2024-11-07 22:12:20 +01:00
Lion
3effe0d4de log zlib error message and regex fix (#146) 2024-11-07 22:05:40 +01:00
Tixx
d58ff960ec Fix github regex 2024-11-07 21:39:18 +01:00
Tixx
f67f8573e0 Log zlib error messages 2024-11-07 21:36:38 +01:00
Lion
8a8e0be1a1 Print message from auth (#141) 2024-11-05 10:32:39 +01:00
Tixx
e0041666ca Clarify and change auth message log 2024-11-05 10:26:10 +01:00
Tixx
ed686333ec Print message from auth 2024-11-05 10:15:10 +01:00
Lion
8938fd84ea Add beammp.gg to the list of allowed links (#143) 2024-11-02 23:29:40 +01:00
Tixx
bd4c9c34a9 Add BeamMP github to the list of allowed links 2024-11-02 22:33:26 +01:00
Tixx
8519e279a7 Add beammp.gg to the list of allowed links 2024-11-02 22:18:46 +01:00
Lion Kortlepel
54895eb1b0 bump version 2024-11-01 12:53:55 +01:00
Lion
1423c1193b Speed up response times by waiting for http requests on another thread. (#137)
If, for example, the client requests the serverlist multiple times and
then tries to login the launcher will first wait for those requests to
finish. Thereby putting the other core communication (such as login) on
hold.
2024-11-01 12:13:21 +01:00
Lion
288e76594d Fix port cli argument (#142)
Fixes --port and -p by proccessing the config file before the cli
arguments, before it would first set --port because it was passed and
then overwrite it with the value from the config. Also removed some
useless code related to cli args.
2024-11-01 12:11:26 +01:00
Tixx
4fdc3c4031 Fix --port 2024-10-20 16:59:00 +02:00
Tixx
708da44fec Remove unused code 2024-10-20 16:57:47 +02:00
Tixx
6b6e304cfd Switch to std::async 2024-10-18 19:23:53 +02:00
Tixx
06cb366bb5 Add mutex to CoreSend 2024-10-16 23:12:02 +02:00
Tixx
0b35f0484f put blocking http requests on another thread 2024-10-16 23:12:02 +02:00
Lion
9dbbd8298d Switch to only timeout on connection (#140) 2024-10-15 19:32:55 +02:00
Tixx
ca9dd1ae75 Switch to only timeout on connection 2024-10-14 20:29:19 +02:00
Lion
9ebd218856 Fix empty modlist (#136)
This PR fixes the launcher getting confused when the server sends an
empty mod list using the new downloading system.
Related server PR: https://github.com/BeamMP/BeamMP-Server/pull/377
2024-10-12 22:10:47 +02:00
Tixx
d9874ce70e Make return from parsemodinfo look better 2024-10-12 21:12:12 +02:00
Tixx
423519f31e Only listen on localhost ipv4 (#134)
This avoids the firewall popup on windows.
2024-10-12 20:58:29 +02:00
Tixx
3f12bb757a Mod info logs and check for old format 2024-10-10 21:35:27 +02:00
Lion Kortlepel
7d52e44434 only listen on localhost ipv4 2024-10-10 16:14:16 +02:00
Tixx
4fbd25b551 Handle new modlist being empty but still valid 2024-10-09 19:41:38 +02:00
Tixx
3cf1a2e51b Add mod info debug log 2024-10-09 19:39:27 +02:00
Lion Kortlepel
49874fd633 Revert "remove 'D' socket initialization code"
This reverts commit 6a23518eff.
2024-10-09 18:00:43 +02:00
Lion Kortlepel
6a23518eff remove 'D' socket initialization code 2024-10-09 17:36:54 +02:00
Lion Kortlepel
3297b3e62e fix not recognizing empty mod lists on new mod list 2024-10-09 17:35:50 +02:00
11 changed files with 67 additions and 48 deletions

6
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,6 @@
Please replace this text <-> with your PR description and leave the below declarations intact.
---
By creating this pull request, I understand that code that is AI generated or otherwise automatically generated may be rejected without further discussion.
I declare that I fully understand all code I pushed into this PR, and wrote all this code myself and own the rights to this code.

1
.gitignore vendored
View File

@@ -12,3 +12,4 @@ Resources/
bin/
compile_commands.json
key
out/

View File

@@ -17,5 +17,4 @@ public:
static void StartProxy();
public:
static bool isDownload;
static inline bool SkipSslVerify = false;
};

View File

@@ -25,7 +25,7 @@ std::vector<char> Comp(std::span<const char> input) {
reinterpret_cast<const Bytef*>(input.data()),
static_cast<uLongf>(input.size()));
if (res != Z_OK) {
error("zlib compress() failed: " + std::to_string(res));
error("zlib compress() failed (code: " + std::to_string(res) + ", message: " + zError(res) + ")");
throw std::runtime_error("zlib compress() failed");
}
debug("zlib compressed " + std::to_string(input.size()) + " B to " + std::to_string(output_size) + " B");
@@ -52,7 +52,7 @@ std::vector<char> DeComp(std::span<const char> input) {
output_buffer.resize(output_buffer.size() * 2);
output_size = output_buffer.size();
} else if (res != Z_OK) {
error("zlib uncompress() failed: " + std::to_string(res));
error("zlib uncompress() failed (code: " + std::to_string(res) + ", message: " + zError(res) + ")");
throw std::runtime_error("zlib uncompress() failed");
} else if (res == Z_OK) {
break;

View File

@@ -30,7 +30,6 @@ void ParseConfig(const nlohmann::json& d) {
}
if (d.contains("CachingDirectory") && d["CachingDirectory"].is_string()) {
CachingDirectory = d["CachingDirectory"].get<std::string>();
info("Mod caching directory: " + CachingDirectory);
}
if (d.contains("Dev") && d["Dev"].is_boolean()) {

View File

@@ -30,8 +30,11 @@
#include <nlohmann/json.hpp>
#include <set>
#include <thread>
#include <mutex>
#include "Options.h"
#include <future>
extern int TraceBack;
std::set<std::string>* ConfList = nullptr;
bool TCPTerminate = false;
@@ -87,7 +90,11 @@ void StartSync(const std::string& Data) {
info("Connecting to server");
}
std::mutex sendMutex;
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);
if (res < 0) {
@@ -97,7 +104,7 @@ void CoreSend(std::string data) {
}
bool IsAllowedLink(const std::string& Link) {
std::regex link_pattern(R"(https:\/\/(?:\w+)?(?:\.)?(?:beammp\.com|discord\.gg|patreon\.com\/BeamMP))");
std::regex link_pattern(R"(https:\/\/(?:\w+)?(?:\.)?(?:beammp\.com|beammp\.gg|github\.com\/BeamMP\/|discord\.gg|patreon\.com\/BeamMP))");
std::smatch link_match;
return std::regex_search(Link, link_match, link_pattern) && link_match.position() == 0;
}
@@ -110,11 +117,15 @@ void Parse(std::string Data, SOCKET CSocket) {
case 'A':
Data = Data.substr(0, 1);
break;
case 'B':
NetReset();
Terminate = true;
TCPTerminate = true;
Data = Code + HTTP::Get("https://backend.beammp.com/servers-info");
case 'B': {
NetReset();
Terminate = true;
TCPTerminate = true;
Data.clear();
auto future = std::async(std::launch::async, []() {
CoreSend("B" + HTTP::Get("https://backend.beammp.com/servers-info"));
});
}
break;
case 'C':
StartSync(Data);
@@ -210,7 +221,10 @@ void Parse(std::string Data, SOCKET CSocket) {
}
Data = "N" + Auth.dump();
} else {
Data = "N" + Login(Data.substr(Data.find(':') + 1));
auto future = std::async(std::launch::async, [data = std::move(Data)]() {
CoreSend("N" + Login(data.substr(data.find(':') + 1)));
});
Data.clear();
}
break;
case 'W':
@@ -226,12 +240,8 @@ void Parse(std::string Data, SOCKET CSocket) {
Data.clear();
break;
}
if (!Data.empty() && CSocket != -1) {
int res = send(CSocket, (Data + "\n").c_str(), int(Data.size()) + 1, 0);
if (res < 0) {
debug("(Core) send failed with error: " + std::to_string(WSAGetLastError()));
}
}
if (!Data.empty())
CoreSend(Data);
}
void GameHandler(SOCKET Client) {
CoreSocket = Client;
@@ -306,7 +316,7 @@ void CoreMain() {
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
iRes = getaddrinfo(nullptr, std::to_string(options.port).c_str(), &hints, &res);
iRes = getaddrinfo("127.0.0.1", std::to_string(options.port).c_str(), &hints, &res);
if (iRes) {
debug("(Core) addr info failed with error: " + std::to_string(iRes));
WSACleanup();

View File

@@ -77,7 +77,7 @@ std::string HTTP::Get(const std::string& IP) {
curl_easy_setopt(curl, CURLOPT_URL, IP.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&Ret);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); // seconds
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); // seconds
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
@@ -105,7 +105,7 @@ std::string HTTP::Post(const std::string& IP, const std::string& Fields) {
struct curl_slist* list = nullptr;
list = curl_slist_append(list, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10); // seconds
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); // seconds
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
res = curl_easy_perform(curl);
curl_slist_free_all(list);
@@ -261,7 +261,7 @@ void HTTP::StartProxy() {
handle_request(req, res);
});
ProxyPort = HTTPProxy.bind_to_any_port("0.0.0.0");
ProxyPort = HTTPProxy.bind_to_any_port("127.0.0.1");
debug("HTTP Proxy listening on port " + std::to_string(ProxyPort));
HTTPProxy.listen_after_bind();
});

View File

@@ -362,10 +362,15 @@ std::string GetSha256HashReallyFast(const std::string& filename) {
}
struct ModInfo {
static std::vector<ModInfo> ParseModInfosFromPacket(const std::string& packet) {
static std::pair<bool, std::vector<ModInfo>> ParseModInfosFromPacket(const std::string& packet) {
bool success = false;
std::vector<ModInfo> modInfos;
try {
auto json = nlohmann::json::parse(packet);
if (json.empty()) {
return std::make_pair(true, modInfos);
}
for (const auto& entry : json) {
ModInfo modInfo {
.FileName = entry["file_name"],
@@ -374,13 +379,13 @@ struct ModInfo {
.HashAlgorithm = entry["hash_algorithm"],
};
modInfos.push_back(modInfo);
success = true;
}
} catch (const std::exception& e) {
debug(std::string("Failed to receive mod list: ") + e.what());
error("Failed to receive mod list!");
// TODO: Cry and die
warn("Failed to receive new mod list format! This server may be outdated, but everything should still work as expected.");
}
return modInfos;
return std::make_pair(success, modInfos);
}
std::string FileName;
size_t FileSize;
@@ -389,6 +394,13 @@ struct ModInfo {
};
void NewSyncResources(SOCKET Sock, const std::string& Mods, const std::vector<ModInfo> ModInfos) {
if (ModInfos.empty()) {
CoreSend("L");
TCPSend("Done", Sock);
info("Done!");
return;
}
if (!SecurityWarning())
return;
@@ -511,11 +523,17 @@ void NewSyncResources(SOCKET Sock, const std::string& Mods, const std::vector<Mo
void SyncResources(SOCKET Sock) {
std::string Ret = Auth(Sock);
auto ModInfos = ModInfo::ParseModInfosFromPacket(Ret);
debug("Mod info: " + Ret);
if (!ModInfos.empty()) {
NewSyncResources(Sock, Ret, ModInfos);
return;
if (Ret.starts_with("R")) {
debug("This server is likely outdated, not trying to parse new mod info format");
} else {
auto [success, modInfo] = ModInfo::ParseModInfosFromPacket(Ret);
if (success) {
NewSyncResources(Sock, Ret, modInfo);
return;
}
}
if (Ret.empty())

View File

@@ -91,6 +91,7 @@ std::string Login(const std::string& fields) {
if (d.contains("message")) {
d.erase("private_key");
d.erase("public_key");
debug("Authentication result: " + d["message"].get<std::string>());
return d.dump();
}
return GetFail("Invalid message parsing!");

View File

@@ -82,10 +82,10 @@ std::string GetEN() {
}
std::string GetVer() {
return "2.2";
return "2.3";
}
std::string GetPatch() {
return ".0";
return ".2";
}
std::string GetEP(const char* P) {
@@ -232,11 +232,9 @@ void LinuxPatch() {
void InitLauncher() {
SetConsoleTitleA(("BeamMP Launcher v" + std::string(GetVer()) + GetPatch()).c_str());
InitLog();
CheckName();
LinuxPatch();
CheckLocalKey();
ConfigInit();
CheckForUpdates(std::string(GetVer()) + GetPatch());
}
#elif defined(__linux__)
@@ -245,7 +243,6 @@ void InitLauncher() {
info("BeamMP Launcher v" + GetVer() + GetPatch());
CheckName();
CheckLocalKey();
ConfigInit();
CheckForUpdates(std::string(GetVer()) + GetPatch());
}
#endif

View File

@@ -38,24 +38,12 @@ int main(int argc, const char** argv) try {
curl_global_init(CURL_GLOBAL_ALL);
#if defined(_WIN32)
system("cls");
#elif defined(__linux__)
system("clear");
#endif
GetEP(argv[0]);
for (int i = 0; i < argc; ++i) {
if (std::string_view(argv[i]) == "--skip-ssl-verify") {
info("SSL verification skip enabled");
HTTP::SkipSslVerify = true;
}
}
InitLog();
ConfigInit();
InitOptions(argc, argv, options);
info("Mod caching directory: " + CachingDirectory);
InitLauncher();
info("IMPORTANT: You MUST keep this window open to play BeamMP!");