From ed77283cb1f8ec8f4ea7375aadb1fc77b4e42e3a Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sat, 26 Aug 2023 20:43:20 -0400 Subject: [PATCH] Send DS's SDL (in minified form) from the AuthSrv. This is to cope with the fallout of Plasma's `/LocalData` option no longer forcing the use of local SDL files. The point of all of these changes is to firm up the contract of what SDL is the correct SDL. --- AuthServ/AuthManifest.h | 6 ++ AuthServ/AuthServer.cpp | 66 ++++++++++++------ AuthServ/AuthServer_Private.h | 1 + SDL/DescriptorDb.cpp | 124 ++++++++++++++++++++++++++++++++++ SDL/DescriptorDb.h | 1 + settings.cpp | 9 +++ settings.h | 2 + 7 files changed, 189 insertions(+), 20 deletions(-) diff --git a/AuthServ/AuthManifest.h b/AuthServ/AuthManifest.h index fcbf0cff..896666fa 100644 --- a/AuthServ/AuthManifest.h +++ b/AuthServ/AuthManifest.h @@ -27,6 +27,9 @@ namespace DS struct AuthFileInfo { AuthFileInfo() : m_fileSize() { } + AuthFileInfo(ST::string filename, uint32_t filesize) + : m_filename(std::move(filename)), m_fileSize(filesize) + { } AuthFileInfo(const AuthFileInfo&) = delete; AuthFileInfo& operator=(const AuthFileInfo&) = delete; @@ -48,6 +51,9 @@ namespace DS size_t fileCount() const { return m_files.size(); } + template + AuthFileInfo& addFile(_Args&&... args) { return m_files.emplace_back(std::forward<_Args>(args)...); } + private: std::vector m_files; }; diff --git a/AuthServ/AuthServer.cpp b/AuthServ/AuthServer.cpp index 98ca58da..cb4f882d 100755 --- a/AuthServ/AuthServer.cpp +++ b/AuthServ/AuthServer.cpp @@ -24,11 +24,14 @@ #include #include #include +#include "SDL/DescriptorDb.h" +#include "SDL/SdlWriter.h" #define NODE_SIZE_MAX (4 * 1024 * 1024) std::list s_authClients; std::mutex s_authClientMutex; +DS::Blob s_minifiedSdl; #define START_REPLY(msgId) \ client.m_buffer.truncate(); \ @@ -563,15 +566,26 @@ void cb_fileList(AuthServer_Private& client) SEND_REPLY(); return; } - ST::string mfsname = ST::format("{}{}_{}.list", DS::Settings::AuthRoot(), - directory, fileext); + DS::AuthManifest mfs; - DS::NetResultCode result = mfs.loadManifest(mfsname.c_str()); - client.m_buffer.write(result); + DS::NetResultCode result = DS::e_NetPending; + + // We may need to manually process SDL files. + if (DS::Settings::SendDescriptorDb() && fileext.compare_i("sdl") == 0) { + mfs.addFile(ST_LITERAL("AllDirtSandStates.sdl"), s_minifiedSdl.size()); + result = DS::e_NetSuccess; + } else { + ST::string mfsname = ST::format("{}{}_{}.list", DS::Settings::AuthRoot(), + directory, fileext); + result = mfs.loadManifest(mfsname.c_str()); + if (result != DS::e_NetSuccess) + ST::printf(stderr, "[Auth] {} requested invalid manifest {}\n", + DS::SockIpAddress(client.m_sock), mfsname); + } + DS_ASSERT(result != DS::e_NetPending); + client.m_buffer.write(result); if (result != DS::e_NetSuccess) { - ST::printf(stderr, "[Auth] {} requested invalid manifest {}\n", - DS::SockIpAddress(client.m_sock), mfsname); client.m_buffer.write(0); // Data packet size } else { uint32_t sizeLocation = client.m_buffer.tell(); @@ -606,20 +620,26 @@ void cb_downloadStart(AuthServer_Private& client) } filename = filename.replace("\\", "/"); - filename = DS::Settings::AuthRoot() + filename; - DS::FileStream* stream = new DS::FileStream(); - try { - stream->open(filename.c_str(), "rb"); - } catch (const DS::FileIOException& ex) { - ST::printf(stderr, "[Auth] Could not open file {}: {}\n[Auth] Requested by {}\n", - filename, ex.what(), DS::SockIpAddress(client.m_sock)); - client.m_buffer.write(DS::e_NetFileNotFound); - client.m_buffer.write(0); // File size - client.m_buffer.write(0); // Chunk offset - client.m_buffer.write(0); // Data packet size - SEND_REPLY(); - delete stream; - return; + DS::Stream* stream; + // Check to see if this is our special SDL file... + if (DS::Settings::SendDescriptorDb() && filename.ends_with(".sdl", ST::case_sensitivity_t::case_insensitive)) { + stream = new DS::BlobStream(s_minifiedSdl); + } else { + filename = DS::Settings::AuthRoot() + filename; + stream = new DS::FileStream(); + try { + static_cast(stream)->open(filename.c_str(), "rb"); + } catch (const DS::FileIOException& ex) { + ST::printf(stderr, "[Auth] Could not open file {}: {}\n[Auth] Requested by {}\n", + filename, ex.what(), DS::SockIpAddress(client.m_sock)); + client.m_buffer.write(DS::e_NetFileNotFound); + client.m_buffer.write(0); // File size + client.m_buffer.write(0); // Chunk offset + client.m_buffer.write(0); // Data packet size + SEND_REPLY(); + delete stream; + return; + } } client.m_buffer.write(DS::e_NetSuccess); @@ -1104,6 +1124,12 @@ void DS::AuthServer_Init(bool restrictLogins) ST::printf(stderr, "Warning: Could not restrict logins: {}\n", ex.what()); } } + + DS::BufferStream stream; + DS::EncryptedStream encStream(&stream, DS::EncryptedStream::Mode::e_write, + DS::EncryptedStream::Type::e_btea, DS::Settings::DroidKey()); + SDL::DescriptorDb::WriteDescriptors(&encStream); + s_minifiedSdl = DS::Blob(stream.buffer(), stream.size()); } void DS::AuthServer_Add(DS::SocketHandle client) diff --git a/AuthServ/AuthServer_Private.h b/AuthServ/AuthServer_Private.h index bb4b0841..dc317159 100644 --- a/AuthServ/AuthServer_Private.h +++ b/AuthServ/AuthServer_Private.h @@ -122,6 +122,7 @@ struct AuthServer_Private : public AuthClient_Private extern std::list s_authClients; extern std::mutex s_authClientMutex; extern std::thread s_authDaemonThread; +extern DS::Blob s_minifiedSdl; extern PGconn* s_postgres; extern uint32_t s_allPlayers; diff --git a/SDL/DescriptorDb.cpp b/SDL/DescriptorDb.cpp index 8f16a16a..ecd4c689 100644 --- a/SDL/DescriptorDb.cpp +++ b/SDL/DescriptorDb.cpp @@ -117,3 +117,127 @@ bool SDL::DescriptorDb::ForLatestDescriptors(descfunc_t functor) } return true; } + +static inline ST::string type_to_typename(const SDL::VarDescriptor& var) +{ + switch (var.m_type) { + case SDL::e_VarInt: + return ST_LITERAL("INT"); + case SDL::e_VarFloat: + return ST_LITERAL("FLOAT"); + case SDL::e_VarBool: + return ST_LITERAL("BOOL"); + case SDL::e_VarString: + return ST_LITERAL("STRING32"); + case SDL::e_VarKey: + return ST_LITERAL("PLKEY"); + case SDL::e_VarStateDesc: + return ST::format("${}", var.m_typeName); + case SDL::e_VarCreatable: + return ST_LITERAL("CREATABLE"); + case SDL::e_VarDouble: + return ST_LITERAL("DOUBLE"); + case SDL::e_VarTime: + return ST_LITERAL("TIME"); + case SDL::e_VarByte: + return ST_LITERAL("BYTE"); + case SDL::e_VarShort: + return ST_LITERAL("SHORT"); + case SDL::e_VarAgeTimeOfDay: + return ST_LITERAL("AGETIMEOFDAY"); + case SDL::e_VarVector3: + return ST_LITERAL("VECTOR3"); + case SDL::e_VarPoint3: + return ST_LITERAL("POINT3"); + case SDL::e_VarRgb: + return ST_LITERAL("RGB"); + case SDL::e_VarRgba: + return ST_LITERAL("RGBA"); + case SDL::e_VarQuaternion: + return ST_LITERAL("QUATERNION"); + case SDL::e_VarRgb8: + return ST_LITERAL("RGB8"); + case SDL::e_VarRgba8: + return ST_LITERAL("RGBA8"); + default: + return ST_LITERAL("INVALID"); + } +} + +static inline ST::string default_to_str(const SDL::VarDescriptor& var) +{ + if (!var.m_default.m_valid) + return {}; + + switch (var.m_type) { + case SDL::e_VarInt: + case SDL::e_VarBool: + case SDL::e_VarByte: + case SDL::e_VarShort: + return ST::string::from_int(var.m_default.m_int); + case SDL::e_VarFloat: + return ST::string::from_float(var.m_default.m_float); + case SDL::e_VarString: + return var.m_default.m_string; + case SDL::e_VarKey: + // The only valid default is "nil", which is the same as leaving the default blank. + // So, let's just save these bytes. + return {}; + case SDL::e_VarDouble: + return ST::string::from_double(var.m_default.m_double); + case SDL::e_VarTime: + return ST::string::from_uint(var.m_default.m_time.m_secs); + case SDL::e_VarVector3: + case SDL::e_VarPoint3: + return ST::format("({},{},{})", var.m_default.m_vector.m_X, + var.m_default.m_vector.m_Y, var.m_default.m_vector.m_Z); + case SDL::e_VarRgb: + return ST::format("({},{},{})", var.m_default.m_color.m_R, + var.m_default.m_color.m_G, var.m_default.m_color.m_B); + case SDL::e_VarRgba: + return ST::format("({},{},{},{})", var.m_default.m_color.m_R, + var.m_default.m_color.m_G, var.m_default.m_color.m_B, + var.m_default.m_color.m_A); + case SDL::e_VarRgb8: + return ST::format("({},{},{})", var.m_default.m_color8.m_R, + var.m_default.m_color8.m_G, var.m_default.m_color8.m_B); + case SDL::e_VarRgba8: + return ST::format("({},{},{},{})", var.m_default.m_color8.m_R, + var.m_default.m_color8.m_G, var.m_default.m_color8.m_B, + var.m_default.m_color8.m_A); + case SDL::e_VarQuaternion: + return ST::format("({},{},{},{})", var.m_default.m_quat.m_X, + var.m_default.m_quat.m_Y, var.m_default.m_quat.m_Z, + var.m_default.m_quat.m_W); + default: + DS_ASSERT(0); + } +} + +void SDL::DescriptorDb::WriteDescriptors(DS::Stream* stream) +{ + for (const auto& desc : s_descriptors) { + stream->writeString(ST::format("STATEDESC {}\n", desc.m_name)); + stream->writeString(ST_LITERAL("{\n")); + stream->writeString(ST::format("\tVERSION {}\n", desc.m_version)); + + for (const auto& var : desc.m_vars) { + stream->writeString(ST::format("\tVAR\t{}\t{}", type_to_typename(var), var.m_name)); + if (!(var.m_flags & VarDescriptor::e_VariableLength)) + stream->writeString(ST::format("[{}]", var.m_size)); + else + stream->writeString(ST_LITERAL("[]")); + + ST::string defValue = default_to_str(var); + if (!defValue.empty()) + stream->writeString(ST::format("\tDEFAULT={}", defValue)); + if (var.m_flags & VarDescriptor::e_AlwaysNew) + stream->writeString(ST_LITERAL("\tDEFAULTOPTION=VAULT")); + if (!var.m_displayOption.empty()) + stream->writeString(ST::format("\tDISPLAYOPTION={}", var.m_displayOption)); + stream->write('\n'); + } + + stream->writeString(ST_LITERAL("}\n")); + } +} diff --git a/SDL/DescriptorDb.h b/SDL/DescriptorDb.h index 515e6565..b42e5232 100644 --- a/SDL/DescriptorDb.h +++ b/SDL/DescriptorDb.h @@ -116,6 +116,7 @@ namespace SDL static StateDescriptor* FindDescriptor(const ST::string& name, int version); static StateDescriptor* FindLatestDescriptor(const ST::string& name); static bool ForLatestDescriptors(descfunc_t functor); + static void WriteDescriptors(DS::Stream* stream); private: DescriptorDb() = delete; diff --git a/settings.cpp b/settings.cpp index c2695961..db95d3e2 100644 --- a/settings.cpp +++ b/settings.cpp @@ -88,6 +88,7 @@ static struct /* Misc */ bool m_statusEnabled; ST::string m_welcome; + bool m_sendDescriptorDb; } s_settings; #define DS_LOADBLOB(outbuffer, fixedsize, params) \ @@ -202,6 +203,8 @@ bool DS::Settings::LoadFrom(const ST::string& filename) s_settings.m_dbDbase = params[1]; } else if (params[0] == "Welcome.Msg") { s_settings.m_welcome = params[1]; + } else if (params[0] == "Auth.SendDescriptorDb") { + s_settings.m_sendDescriptorDb = params[1].to_bool(); } else { ST::printf(stderr, "Warning: Unknown setting '{}' ignored\n", params[0]); } @@ -221,6 +224,7 @@ void DS::Settings::UseDefaults() s_settings.m_lobbyPort = ST_LITERAL("14617"); s_settings.m_statusPort = ST_LITERAL("8080"); s_settings.m_statusEnabled = true; + s_settings.m_sendDescriptorDb = true; s_settings.m_fileRoot = ST_LITERAL("./data"); s_settings.m_authRoot = ST_LITERAL("./authdata"); @@ -348,3 +352,8 @@ void DS::Settings::SetWelcomeMsg(const ST::string& welcome) { s_settings.m_welcome = welcome; } + +bool DS::Settings::SendDescriptorDb() +{ + return s_settings.m_sendDescriptorDb; +} diff --git a/settings.h b/settings.h index cf6eec67..d24ec495 100644 --- a/settings.h +++ b/settings.h @@ -80,6 +80,8 @@ namespace DS ST::string WelcomeMsg(); void SetWelcomeMsg(const ST::string& welcome); + bool SendDescriptorDb(); + bool LoadFrom(const ST::string& filename); void UseDefaults(); }