From 753dda6231bbb2adf585bbc916c0b220e816fcdc Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Wed, 5 Jan 2022 19:13:54 +0000 Subject: refactor to allow servers to reregister themselves in heartbeat --- NorthstarDedicatedTest/masterserver.cpp | 88 ++++++++++++++++++++----------- NorthstarDedicatedTest/masterserver.h | 2 + NorthstarDedicatedTest/modmanager.cpp | 28 +++++++++- NorthstarDedicatedTest/rpakfilesystem.cpp | 6 +-- 4 files changed, 89 insertions(+), 35 deletions(-) diff --git a/NorthstarDedicatedTest/masterserver.cpp b/NorthstarDedicatedTest/masterserver.cpp index 74bd9af5..d34065c0 100644 --- a/NorthstarDedicatedTest/masterserver.cpp +++ b/NorthstarDedicatedTest/masterserver.cpp @@ -686,32 +686,6 @@ void MasterServerManager::AddSelfToServerList(int port, int authPort, char* name m_ownServerId[0] = 0; m_ownServerAuthToken[0] = 0; - // build modinfo obj - rapidjson_document modinfoDoc; - modinfoDoc.SetObject(); - modinfoDoc.AddMember("Mods", rapidjson_document::GenericValue(rapidjson::kArrayType), modinfoDoc.GetAllocator()); - - int currentModIndex = 0; - for (Mod& mod : g_ModManager->m_loadedMods) - { - if (!mod.Enabled || (!mod.RequiredOnClient && !mod.Pdiff.size())) - continue; - - modinfoDoc["Mods"].PushBack(rapidjson_document::GenericValue(rapidjson::kObjectType), modinfoDoc.GetAllocator()); - modinfoDoc["Mods"][currentModIndex].AddMember("Name", rapidjson::StringRef(&mod.Name[0]), modinfoDoc.GetAllocator()); - modinfoDoc["Mods"][currentModIndex].AddMember("Version", rapidjson::StringRef(&mod.Version[0]), modinfoDoc.GetAllocator()); - modinfoDoc["Mods"][currentModIndex].AddMember("RequiredOnClient", mod.RequiredOnClient, modinfoDoc.GetAllocator()); - modinfoDoc["Mods"][currentModIndex].AddMember("Pdiff", rapidjson::StringRef(&mod.Pdiff[0]), modinfoDoc.GetAllocator()); - - currentModIndex++; - } - - rapidjson::StringBuffer buffer; - buffer.Clear(); - rapidjson::Writer writer(buffer); - modinfoDoc.Accept(writer); - const char* modInfoString = buffer.GetString(); - CURL* curl = curl_easy_init(); SetCommonHttpClientOptions(curl); @@ -723,7 +697,7 @@ void MasterServerManager::AddSelfToServerList(int port, int authPort, char* name curl_mime* mime = curl_mime_init(curl); curl_mimepart* part = curl_mime_addpart(mime); - curl_mime_data(part, modInfoString, buffer.GetSize()); + curl_mime_data(part, m_ownModInfoJson.c_str(), m_ownModInfoJson.size()); curl_mime_name(part, "modinfo"); curl_mime_filename(part, "modinfo.json"); curl_mime_type(part, "application/json"); @@ -787,8 +761,8 @@ void MasterServerManager::AddSelfToServerList(int port, int authPort, char* name goto REQUEST_END_CLEANUP; } - strncpy(m_ownServerId, serverAddedJson["id"].GetString(), sizeof(m_ownServerId)); - m_ownServerId[sizeof(m_ownServerId) - 1] = 0; + strncpy(m_ownServerId, serverAddedJson["id"].GetString(), sizeof(m_ownServerId)); + m_ownServerId[sizeof(m_ownServerId) - 1] = 0; strncpy(m_ownServerAuthToken, serverAddedJson["serverAuthToken"].GetString(), sizeof(m_ownServerAuthToken)); m_ownServerAuthToken[sizeof(m_ownServerAuthToken) - 1] = 0; @@ -805,13 +779,65 @@ void MasterServerManager::AddSelfToServerList(int port, int authPort, char* name std::string readBuffer; curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); - curl_easy_setopt(curl, CURLOPT_URL, fmt::format("{}/server/heartbeat?id={}&playerCount={}", Cvar_ns_masterserver_hostname->m_pszString, m_ownServerId, g_ServerAuthenticationManager->m_additionalPlayerData.size()).c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L); + + // send all registration info so we have all necessary info to reregister our server if masterserver goes down, without a restart + // this isn't threadsafe :terror: + { + char* escapedNameNew = curl_easy_escape(curl, Cvar_ns_server_name->m_pszString, NULL); + char* escapedDescNew = curl_easy_escape(curl, Cvar_ns_server_desc->m_pszString, NULL); + char* escapedMapNew = curl_easy_escape(curl, g_pHostState->m_levelName, NULL); + char* escapedPlaylistNew = curl_easy_escape(curl, GetCurrentPlaylistName(), NULL); + char* escapedPasswordNew = curl_easy_escape(curl, Cvar_ns_server_password->m_pszString, NULL); + + int maxPlayers = 6; + char* maxPlayersVar = GetCurrentPlaylistVar("max_players", false); + if (maxPlayersVar) // GetCurrentPlaylistVar can return null so protect against this + maxPlayers = std::stoi(maxPlayersVar); + + curl_easy_setopt(curl, CURLOPT_URL, fmt::format("{}/server/update_values?id={}&port={}&authPort={}&name={}&description={}&map={}&playlist={}&playerCount={}&maxPlayers={}&password={}", Cvar_ns_masterserver_hostname->m_pszString, m_ownServerId, Cvar_hostport->m_nValue, Cvar_ns_player_auth_port->m_nValue, escapedNameNew, escapedDescNew, escapedMapNew, escapedPlaylistNew, g_ServerAuthenticationManager->m_additionalPlayerData.size(), maxPlayers, escapedPasswordNew).c_str()); + + curl_free(escapedNameNew); + curl_free(escapedDescNew); + curl_free(escapedMapNew); + curl_free(escapedPlaylistNew); + curl_free(escapedPasswordNew); + } + + curl_mime* mime = curl_mime_init(curl); + curl_mimepart* part = curl_mime_addpart(mime); + + curl_mime_data(part, m_ownModInfoJson.c_str(), m_ownModInfoJson.size()); + curl_mime_name(part, "modinfo"); + curl_mime_filename(part, "modinfo.json"); + curl_mime_type(part, "application/json"); + + curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime); CURLcode result = curl_easy_perform(curl); - if (result != CURLcode::CURLE_OK) + if (result == CURLcode::CURLE_OK) + { + rapidjson_document serverAddedJson; + serverAddedJson.Parse(readBuffer.c_str()); + + if (!serverAddedJson.HasParseError() && serverAddedJson.IsObject()) + { + if (serverAddedJson.HasMember("id") && serverAddedJson["id"].IsString()) + { + strncpy(m_ownServerId, serverAddedJson["id"].GetString(), sizeof(m_ownServerId)); + m_ownServerId[sizeof(m_ownServerId) - 1] = 0; + } + + if (serverAddedJson.HasMember("serverAuthToken") && serverAddedJson["serverAuthToken"].IsString()) + { + strncpy(m_ownServerAuthToken, serverAddedJson["serverAuthToken"].GetString(), sizeof(m_ownServerAuthToken)); + m_ownServerAuthToken[sizeof(m_ownServerAuthToken) - 1] = 0; + } + } + } + else spdlog::warn("Heartbeat failed with error {}", curl_easy_strerror(result)); curl_easy_cleanup(curl); diff --git a/NorthstarDedicatedTest/masterserver.h b/NorthstarDedicatedTest/masterserver.h index d3c83052..d7071b6c 100644 --- a/NorthstarDedicatedTest/masterserver.h +++ b/NorthstarDedicatedTest/masterserver.h @@ -72,6 +72,8 @@ public: char m_ownServerAuthToken[33]; char m_ownClientAuthToken[33]; + std::string m_ownModInfoJson; + bool m_bOriginAuthWithMasterServerDone = false; bool m_bOriginAuthWithMasterServerInProgress = false; diff --git a/NorthstarDedicatedTest/modmanager.cpp b/NorthstarDedicatedTest/modmanager.cpp index 23dd2d6e..c5f1bf49 100644 --- a/NorthstarDedicatedTest/modmanager.cpp +++ b/NorthstarDedicatedTest/modmanager.cpp @@ -2,7 +2,7 @@ #include "modmanager.h" #include "convar.h" #include "concommand.h" - +#include "masterserver.h" #include "rapidjson/error/en.h" #include "rapidjson/document.h" #include "rapidjson/ostreamwrapper.h" @@ -355,6 +355,32 @@ void ModManager::LoadMods() } } + // build modinfo obj for masterserver + rapidjson_document modinfoDoc; + modinfoDoc.SetObject(); + modinfoDoc.AddMember("Mods", rapidjson_document::GenericValue(rapidjson::kArrayType), modinfoDoc.GetAllocator()); + + int currentModIndex = 0; + for (Mod& mod : m_loadedMods) + { + if (!mod.Enabled || (!mod.RequiredOnClient && !mod.Pdiff.size())) + continue; + + modinfoDoc["Mods"].PushBack(rapidjson_document::GenericValue(rapidjson::kObjectType), modinfoDoc.GetAllocator()); + modinfoDoc["Mods"][currentModIndex].AddMember("Name", rapidjson::StringRef(&mod.Name[0]), modinfoDoc.GetAllocator()); + modinfoDoc["Mods"][currentModIndex].AddMember("Version", rapidjson::StringRef(&mod.Version[0]), modinfoDoc.GetAllocator()); + modinfoDoc["Mods"][currentModIndex].AddMember("RequiredOnClient", mod.RequiredOnClient, modinfoDoc.GetAllocator()); + modinfoDoc["Mods"][currentModIndex].AddMember("Pdiff", rapidjson::StringRef(&mod.Pdiff[0]), modinfoDoc.GetAllocator()); + + currentModIndex++; + } + + rapidjson::StringBuffer buffer; + buffer.Clear(); + rapidjson::Writer writer(buffer); + modinfoDoc.Accept(writer); + g_MasterServerManager->m_ownModInfoJson = std::string(buffer.GetString()); + m_hasLoadedMods = true; } diff --git a/NorthstarDedicatedTest/rpakfilesystem.cpp b/NorthstarDedicatedTest/rpakfilesystem.cpp index 006a57c5..5dfb2386 100644 --- a/NorthstarDedicatedTest/rpakfilesystem.cpp +++ b/NorthstarDedicatedTest/rpakfilesystem.cpp @@ -6,8 +6,8 @@ typedef void*(*LoadCommonPaksForMapType)(char* map); LoadCommonPaksForMapType LoadCommonPaksForMap; -typedef void*(*LoadPakSyncType)(char* path, void* unknownSingleton, int flags); -typedef void*(*LoadPakAsyncType)(char* path, void* unknownSingleton, int flags, void* callback0, void* callback1); +typedef void*(*LoadPakSyncType)(const char* path, void* unknownSingleton, int flags); +typedef void*(*LoadPakAsyncType)(const char* path, void* unknownSingleton, int flags, void* callback0, void* callback1); // there are more i'm just too lazy to add struct PakLoadFuncs @@ -20,7 +20,7 @@ struct PakLoadFuncs PakLoadFuncs* g_pakLoadApi; void** pUnknownPakLoadSingleton; -void LoadPakAsync(char* path) +void LoadPakAsync(const char* path) { g_pakLoadApi->LoadPakAsync(path, *pUnknownPakLoadSingleton, 2, nullptr, nullptr); } -- cgit v1.2.3