From 3299267976a95b12186a68502348dd98a8eabe2e Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Mon, 25 Nov 2013 11:55:29 -0500 Subject: [PATCH] Integrate SecurePreloader into pfPatcher --- Sources/Plasma/Apps/plClient/CMakeLists.txt | 1 - Sources/Plasma/Apps/plClient/plClient.cpp | 45 +- Sources/Plasma/Apps/plClient/plClient.h | 1 - Sources/Plasma/CoreLib/hsStream.h | 2 +- Sources/Plasma/FeatureLib/CMakeLists.txt | 1 - .../Plasma/FeatureLib/inc/pfAllCreatables.h | 1 - .../Plasma/FeatureLib/pfPatcher/pfPatcher.cpp | 170 ++++++- .../Plasma/FeatureLib/pfPatcher/pfPatcher.h | 13 + .../pfSecurePreloader/CMakeLists.txt | 22 - .../pfSecurePreloader/pfSecurePreloader.cpp | 414 ------------------ .../pfSecurePreloader/pfSecurePreloader.h | 96 ---- .../pfSecurePreloaderCreatable.h | 57 --- .../Plasma/NucleusLib/inc/plCreatableIndex.h | 4 +- .../NucleusLib/pnKeyedObject/plFixedKey.cpp | 2 - .../NucleusLib/pnKeyedObject/plFixedKey.h | 1 - .../PubUtilLib/plAgeLoader/plResPatcher.cpp | 29 +- .../PubUtilLib/plAgeLoader/plResPatcher.h | 2 + .../PubUtilLib/plFile/plSecureStream.cpp | 8 +- .../PubUtilLib/plFile/plStreamSource.cpp | 28 +- .../Plasma/PubUtilLib/plFile/plStreamSource.h | 9 +- .../PubUtilLib/plMessage/CMakeLists.txt | 1 - .../PubUtilLib/plMessage/plMessageCreatable.h | 3 - .../PubUtilLib/plMessage/plPreloaderMsg.h | 67 --- .../plNetClientComm/plNetClientComm.cpp | 4 + Sources/Tools/MaxMain/CMakeLists.txt | 1 - Sources/Tools/MaxPlasmaLights/CMakeLists.txt | 1 - 26 files changed, 241 insertions(+), 742 deletions(-) delete mode 100644 Sources/Plasma/FeatureLib/pfSecurePreloader/CMakeLists.txt delete mode 100644 Sources/Plasma/FeatureLib/pfSecurePreloader/pfSecurePreloader.cpp delete mode 100644 Sources/Plasma/FeatureLib/pfSecurePreloader/pfSecurePreloader.h delete mode 100644 Sources/Plasma/FeatureLib/pfSecurePreloader/pfSecurePreloaderCreatable.h delete mode 100644 Sources/Plasma/PubUtilLib/plMessage/plPreloaderMsg.h diff --git a/Sources/Plasma/Apps/plClient/CMakeLists.txt b/Sources/Plasma/Apps/plClient/CMakeLists.txt index e36b338b..811008e1 100644 --- a/Sources/Plasma/Apps/plClient/CMakeLists.txt +++ b/Sources/Plasma/Apps/plClient/CMakeLists.txt @@ -86,7 +86,6 @@ target_link_libraries(plClient pfJournalBook) target_link_libraries(plClient pfLocalizationMgr) target_link_libraries(plClient pfMessage) target_link_libraries(plClient pfPython) -target_link_libraries(plClient pfSecurePreloader) target_link_libraries(plClient pfSurface) target_link_libraries(plClient plAgeDescription) target_link_libraries(plClient plAgeLoader) diff --git a/Sources/Plasma/Apps/plClient/plClient.cpp b/Sources/Plasma/Apps/plClient/plClient.cpp index d68cfedc..8fdb544f 100644 --- a/Sources/Plasma/Apps/plClient/plClient.cpp +++ b/Sources/Plasma/Apps/plClient/plClient.cpp @@ -73,7 +73,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "pnMessage/plCameraMsg.h" #include "plMessage/plTransitionMsg.h" #include "plMessage/plLinkToAgeMsg.h" -#include "plMessage/plPreloaderMsg.h" #include "plMessage/plNetCommMsgs.h" #include "plMessage/plAgeLoadedMsg.h" #include "plMessage/plResPatcherMsg.h" @@ -151,7 +150,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plNetCommon/plNetCommonConstants.h" #include "plNetGameLib/plNetGameLib.h" -#include "pfSecurePreloader/pfSecurePreloader.h" #include "pfLocalizationMgr/pfLocalizationMgr.h" #include "pfPatcher/plManifests.h" @@ -312,11 +310,6 @@ bool plClient::Shutdown() plAgeLoader::GetInstance()->UnRegisterAs(kAgeLoader_KEY); // deletes instance plAgeLoader::SetInstance(nil); } - - if (pfSecurePreloader::GetInstance()) - { - pfSecurePreloader::GetInstance()->Shutdown(); // will unregister itself - } if (fInputManager) { @@ -853,14 +846,6 @@ bool plClient::MsgReceive(plMessage* msg) return true; } - //============================================================================ - // plPreloaderMsg - //============================================================================ - if (plPreloaderMsg * preloaderMsg = plPreloaderMsg::ConvertNoRef(msg)) { - IHandlePreloaderMsg(preloaderMsg); - return true; - } - //============================================================================ // plResPatcherMsg //============================================================================ @@ -1565,8 +1550,7 @@ bool plClient::StartInit() plgDispatch::Dispatch()->RegisterForExactType(plNetCommAuthMsg::Index(), GetKey()); plNetClientMgr::GetInstance()->Init(); plAgeLoader::GetInstance()->Init(); - pfSecurePreloader::GetInstance()->Init(); - + plCmdIfaceModMsg* pModMsg2 = new plCmdIfaceModMsg; pModMsg2->SetBCastFlag(plMessage::kBCastByExactType); pModMsg2->SetSender(fConsole->GetKey()); @@ -2516,27 +2500,6 @@ void plClient::ICompleteInit () { clientMsg->Send(); } -//============================================================================ -void plClient::IHandlePreloaderMsg (plPreloaderMsg * msg) { - - plgDispatch::Dispatch()->UnRegisterForExactType(plPreloaderMsg::Index(), GetKey()); - if (pfSecurePreloader* sp = pfSecurePreloader::GetInstance()) - sp->Shutdown(); - - if (!msg->fSuccess) { - char str[1024]; - StrPrintf( - str, - arrsize(str), - "Secure file preloader failed" - ); - plNetClientApp::GetInstance()->QueueDisableNet(true, str); - return; - } - - IPatchGlobalAgeFiles(); -} - //============================================================================ void plClient::IHandlePatcherMsg (plResPatcherMsg * msg) { plgDispatch::Dispatch()->UnRegisterForExactType(plResPatcherMsg::Index(), GetKey()); @@ -2569,8 +2532,6 @@ void plClient::IHandleNetCommAuthMsg (plNetCommAuthMsg * msg) { return; } - plgDispatch::Dispatch()->RegisterForExactType(plPreloaderMsg::Index(), GetKey()); - - // Precache our secure files - pfSecurePreloader::GetInstance()->Start(); + // Patch them global files! + IPatchGlobalAgeFiles(); } diff --git a/Sources/Plasma/Apps/plClient/plClient.h b/Sources/Plasma/Apps/plClient/plClient.h index cdc482c0..108b9c36 100644 --- a/Sources/Plasma/Apps/plClient/plClient.h +++ b/Sources/Plasma/Apps/plClient/plClient.h @@ -181,7 +181,6 @@ protected: void ICompleteInit (); void IOnAsyncInitComplete (); void IHandlePatcherMsg (plResPatcherMsg * msg); - void IHandlePreloaderMsg (plPreloaderMsg * msg); void IHandleNetCommAuthMsg (plNetCommAuthMsg * msg); bool IHandleAgeLoaded2Msg (plAgeLoaded2Msg * msg); diff --git a/Sources/Plasma/CoreLib/hsStream.h b/Sources/Plasma/CoreLib/hsStream.h index b0caf96c..c80787cf 100644 --- a/Sources/Plasma/CoreLib/hsStream.h +++ b/Sources/Plasma/CoreLib/hsStream.h @@ -350,7 +350,7 @@ public: virtual ~hsRAMStream(); virtual bool Open(const plFileName &, const char *) { hsAssert(0, "hsRAMStream::Open NotImplemented"); return false; } - virtual bool Close() { hsAssert(0, "hsRAMStream::Close NotImplemented"); return false; } + virtual bool Close() { return false; } virtual bool AtEnd(); diff --git a/Sources/Plasma/FeatureLib/CMakeLists.txt b/Sources/Plasma/FeatureLib/CMakeLists.txt index 07552faa..3b34f88d 100644 --- a/Sources/Plasma/FeatureLib/CMakeLists.txt +++ b/Sources/Plasma/FeatureLib/CMakeLists.txt @@ -19,5 +19,4 @@ add_subdirectory(pfLocalizationMgr) add_subdirectory(pfMessage) add_subdirectory(pfPatcher) add_subdirectory(pfPython) -add_subdirectory(pfSecurePreloader) add_subdirectory(pfSurface) diff --git a/Sources/Plasma/FeatureLib/inc/pfAllCreatables.h b/Sources/Plasma/FeatureLib/inc/pfAllCreatables.h index e45f3bd5..8ac3f02f 100644 --- a/Sources/Plasma/FeatureLib/inc/pfAllCreatables.h +++ b/Sources/Plasma/FeatureLib/inc/pfAllCreatables.h @@ -57,6 +57,5 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "pfCCR/plCCRCreatable.h" #include "pfJournalBook/pfJournalBookCreatable.h" #include "pfGameMgr/pfGameMgrCreatables.h" -#include "pfSecurePreloader/pfSecurePreloaderCreatable.h" #endif // pfAllCreatables_inc diff --git a/Sources/Plasma/FeatureLib/pfPatcher/pfPatcher.cpp b/Sources/Plasma/FeatureLib/pfPatcher/pfPatcher.cpp index 080b9c01..d4705e62 100644 --- a/Sources/Plasma/FeatureLib/pfPatcher/pfPatcher.cpp +++ b/Sources/Plasma/FeatureLib/pfPatcher/pfPatcher.cpp @@ -68,7 +68,7 @@ struct pfPatcherWorker : public hsThread /** Represents a File/Auth download request */ struct Request { - enum { kFile, kManifest }; + enum { kFile, kManifest, kSecurePreloader, kAuthFile, kPythonList, kSdlList }; plString fName; uint8_t fType; @@ -101,6 +101,7 @@ struct pfPatcherWorker : public hsThread pfPatcher::CompletionFunc fOnComplete; pfPatcher::FileDownloadFunc fFileBeginDownload; pfPatcher::FileDownloadFunc fFileDownloaded; + pfPatcher::GameCodeDiscoverFunc fGameCodeDiscovered; pfPatcher::ProgressTickFunc fProgressTick; pfPatcher* fParent; @@ -119,6 +120,7 @@ struct pfPatcherWorker : public hsThread bool IssueRequest(); virtual hsError Run(); void ProcessFile(); + void WhitelistFile(const plFileName& file, bool justDownloaded, hsStream* s=nullptr); }; // =================================================== @@ -150,6 +152,13 @@ class pfPatcherStream : public plZlibStream } public: + pfPatcherStream(pfPatcherWorker* parent, const plFileName& filename, uint64_t size) + : fParent(parent), fFilename(filename), fFlags(0), fBytesWritten(0) + { + fParent->fTotalBytes += size; + fOutput = new hsRAMStream; + } + pfPatcherStream(pfPatcherWorker* parent, const plFileName& filename, const NetCliFileManifestEntry& entry) : fParent(parent), fFlags(entry.flags), fBytesWritten(0) { @@ -179,6 +188,15 @@ public: return fOutput->Write(count, buf); } + virtual bool AtEnd() { return fOutput->AtEnd(); } + virtual uint32_t GetEOF() { return fOutput->GetEOF(); } + virtual uint32_t GetPosition() const { return fOutput->GetPosition(); } + virtual uint32_t GetSizeLeft() const { return fOutput->GetSizeLeft(); } + virtual uint32_t Read(uint32_t count, void* buf) { return fOutput->Read(count, buf); } + virtual void Rewind() { fOutput->Rewind(); } + virtual void SetPosition(uint32_t pos) { fOutput->SetPosition(pos); } + virtual void Skip(uint32_t deltaByteCount) { fOutput->Skip(deltaByteCount); } + void Begin() { fDLStartTime = hsTimer::GetSysSeconds(); } plFileName GetFileName() const { return fFilename; } void Unlink() const { plFileSystem::Unlink(fFilename); } @@ -186,20 +204,94 @@ public: // =================================================== -static void IFileManifestDownloadCB(ENetError result, void* param, const wchar_t group[], const NetCliFileManifestEntry manifest[], unsigned entryCount) +static void IAuthThingDownloadCB(ENetError result, void* param, const plFileName& filename, hsStream* writer) +{ + pfPatcherWorker* patcher = static_cast(param); + + if (IS_NET_SUCCESS(result)) { + PatcherLogGreen("\tDownloaded Legacy File '%s'", filename.AsString().c_str()); + patcher->IssueRequest(); + + // Now, we pass our RAM-backed file to the game code handlers. In the main client, + // this will trickle down and add a new friend to plStreamSource. This should never + // happen in any other app... + writer->Rewind(); + patcher->WhitelistFile(filename, true, writer); + } else { + PatcherLogRed("\tDownloaded Failed: File '%s'", filename.AsString().c_str()); + patcher->EndPatch(result, filename.AsString()); + } +} + +static void IGotAuthFileList(ENetError result, void* param, const NetCliAuthFileInfo infoArr[], unsigned infoCount) { pfPatcherWorker* patcher = static_cast(param); if (IS_NET_SUCCESS(result)) { - PatcherLogGreen("\tDownloaded Manifest '%S'", group); + // so everything goes directly into the Requests deque because AuthSrv lists + // don't have any hashes attached. WHY did eap think this was a good idea?!?! { - hsTempMutexLock lock(patcher->fFileMut); - for (unsigned i = 0; i < entryCount; ++i) - patcher->fQueuedFiles.push_back(manifest[i]); - patcher->fFileSignal.Signal(); + hsTempMutexLock lock(patcher->fRequestMut); + for (unsigned i = 0; i < infoCount; ++i) { + PatcherLogYellow("\tEnqueuing Legacy File '%S'", infoArr[i].filename); + + plFileName fn = plString::FromWchar(infoArr[i].filename); + plFileSystem::CreateDir(fn.StripFileName()); + + // We purposefully do NOT Open this stream! This uses a special auth-file constructor that + // utilizes a backing hsRAMStream. This will be fed to plStreamSource later... + pfPatcherStream* s = new pfPatcherStream(patcher, fn, infoArr[i].filesize); + pfPatcherWorker::Request req = pfPatcherWorker::Request(fn.AsString(), pfPatcherWorker::Request::kAuthFile, s); + patcher->fRequests.push_back(req); + } } patcher->IssueRequest(); } else { + PatcherLogRed("\tSHIT! Some legacy manifest phailed"); + patcher->EndPatch(result, "SecurePreloader failed"); + } +} + +static void IHandleManifestDownload(pfPatcherWorker* patcher, const wchar_t group[], const NetCliFileManifestEntry manifest[], unsigned entryCount) +{ + PatcherLogGreen("\tDownloaded Manifest '%S'", group); + { + hsTempMutexLock lock(patcher->fFileMut); + for (unsigned i = 0; i < entryCount; ++i) + patcher->fQueuedFiles.push_back(manifest[i]); + patcher->fFileSignal.Signal(); + } + patcher->IssueRequest(); +} + +static void IPreloaderManifestDownloadCB(ENetError result, void* param, const wchar_t group[], const NetCliFileManifestEntry manifest[], unsigned entryCount) +{ + pfPatcherWorker* patcher = static_cast(param); + + if (IS_NET_SUCCESS(result)) + IHandleManifestDownload(patcher, group, manifest, entryCount); + else { + PatcherLogYellow("\tWARNING: *** Falling back to AuthSrv file lists to get game code ***"); + + // so, we need to ask the AuthSrv about our game code + { + hsTempMutexLock lock(patcher->fRequestMut); + patcher->fRequests.push_back(pfPatcherWorker::Request(plString::Null, pfPatcherWorker::Request::kPythonList)); + patcher->fRequests.push_back(pfPatcherWorker::Request(plString::Null, pfPatcherWorker::Request::kSdlList)); + } + + // continue pumping requests + patcher->IssueRequest(); + } +} + +static void IFileManifestDownloadCB(ENetError result, void* param, const wchar_t group[], const NetCliFileManifestEntry manifest[], unsigned entryCount) +{ + pfPatcherWorker* patcher = static_cast(param); + + if (IS_NET_SUCCESS(result)) + IHandleManifestDownload(patcher, group, manifest, entryCount); + else { PatcherLogRed("\tDownload Failed: Manifest '%S'", group); patcher->EndPatch(result, plString::FromWchar(group)); } @@ -213,8 +305,7 @@ static void IFileThingDownloadCB(ENetError result, void* param, const plFileName if (IS_NET_SUCCESS(result)) { PatcherLogGreen("\tDownloaded File '%s'", stream->GetFileName().AsString().c_str()); - if (patcher->fFileDownloaded) - patcher->fFileDownloaded(stream->GetFileName()); + patcher->WhitelistFile(stream->GetFileName(), true); patcher->IssueRequest(); } else { PatcherLogRed("\tDownloaded Failed: File '%s'", stream->GetFileName().AsString().c_str()); @@ -299,6 +390,25 @@ bool pfPatcherWorker::IssueRequest() case Request::kManifest: NetCliFileManifestRequest(IFileManifestDownloadCB, this, req.fName.ToWchar()); break; + case Request::kSecurePreloader: + // so, yeah, this is usually the "SecurePreloader" manifest on the file server... + // except on legacy servers, this may not exist, so we need to fall back without nuking everything! + NetCliFileManifestRequest(IPreloaderManifestDownloadCB, this, req.fName.ToWchar()); + break; + case Request::kAuthFile: + // ffffffuuuuuu + req.fStream->Begin(); + if (fFileBeginDownload) + fFileBeginDownload(req.fStream->GetFileName()); + + NetCliAuthFileRequest(req.fName, req.fStream, IAuthThingDownloadCB, this); + break; + case Request::kPythonList: + NetCliAuthFileListRequest(L"Python", L"pak", IGotAuthFileList, this); + break; + case Request::kSdlList: + NetCliAuthFileListRequest(L"SDL", L"sdl", IGotAuthFileList, this); + break; DEFAULT_FATAL(req.fType); } @@ -347,7 +457,7 @@ void pfPatcherWorker::ProcessFile() const NetCliFileManifestEntry& entry = fQueuedFiles.front(); // eap sucks - plString clName = plString::FromWchar(entry.clientName); + plFileName clName = plString::FromWchar(entry.clientName); plString dlName = plString::FromWchar(entry.downloadName); // Check to see if ours matches @@ -358,6 +468,7 @@ void pfPatcherWorker::ProcessFile() srvMD5.SetFromHexString(plString::FromWchar(entry.md5, 32).c_str()); if (cliMD5 == srvMD5) { + WhitelistFile(clName, false); fQueuedFiles.pop_front(); continue; } @@ -379,6 +490,33 @@ void pfPatcherWorker::ProcessFile() } while (!fQueuedFiles.empty()); } +void pfPatcherWorker::WhitelistFile(const plFileName& file, bool justDownloaded, hsStream* stream) +{ + // if this is a newly downloaded file, fire off a completion callback + if (justDownloaded && fFileDownloaded) + fFileDownloaded(file); + + // we want to whitelist our game code, so here we go... + if (fGameCodeDiscovered) { + plString ext = file.GetFileExt(); + if (ext.CompareI("pak") == 0 || ext.CompareI("sdl") == 0) { + if (!stream) { + stream = new hsUNIXStream; + stream->Open(file, "rb"); + } + + // if something terrible goes wrong (eg bad encryption), we can exit sanely + // callback eats stream + if (!fGameCodeDiscovered(file, stream)) + EndPatch(kNetErrInternalError, "SecurePreloader failed."); + } + } else if (stream) { + // no dad gum memory leaks, m'kay? + stream->Close(); + delete stream; + } +} + // =================================================== plStatusLog* pfPatcher::GetLog() @@ -414,6 +552,11 @@ void pfPatcher::OnFileDownloaded(FileDownloadFunc cb) fWorker->fFileDownloaded = cb; } +void pfPatcher::OnGameCodeDiscovery(GameCodeDiscoverFunc cb) +{ + fWorker->fGameCodeDiscovered = cb; +} + void pfPatcher::OnProgressTick(ProgressTickFunc cb) { fWorker->fProgressTick = cb; @@ -421,6 +564,12 @@ void pfPatcher::OnProgressTick(ProgressTickFunc cb) // =================================================== +void pfPatcher::RequestGameCode() +{ + hsTempMutexLock lock(fWorker->fRequestMut); + fWorker->fRequests.push_back(pfPatcherWorker::Request("SecurePreloader", pfPatcherWorker::Request::kSecurePreloader)); +} + void pfPatcher::RequestManifest(const plString& mfs) { hsTempMutexLock lock(fWorker->fRequestMut); @@ -447,4 +596,3 @@ bool pfPatcher::Start() } return false; } - diff --git a/Sources/Plasma/FeatureLib/pfPatcher/pfPatcher.h b/Sources/Plasma/FeatureLib/pfPatcher/pfPatcher.h index 5262a1ec..6610b722 100644 --- a/Sources/Plasma/FeatureLib/pfPatcher/pfPatcher.h +++ b/Sources/Plasma/FeatureLib/pfPatcher/pfPatcher.h @@ -52,6 +52,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com class plFileName; class plStatusLog; +class hsStream; /** Plasma File Patcher * This is used to patch the client with one or many manifests at once. It assumes that @@ -72,6 +73,11 @@ public: /** Represents a function that takes (const plFileName&) on an interesting file operation. */ typedef std::function FileDownloadFunc; + /** Represents a function that takes (const plFileName&, hsStream*) on game code discovery. + * You are responsible for closing and deleting the provided stream. + */ + typedef std::function GameCodeDiscoverFunc; + /** Represents a function that takes (bytesDLed, totalBytes, statsStr) as a progress indicator. */ typedef std::function ProgressTickFunc; @@ -94,12 +100,19 @@ public: */ void OnFileDownloaded(FileDownloadFunc cb); + /** This is called when the patcher discovers an up-to-date Python package or SDL file. + * \remarks This can be called from any thread when the patcher downloads or encounters an up-to-date + * python package or SDL file that the server knows about. + */ + void OnGameCodeDiscovery(GameCodeDiscoverFunc cb); + /** Set a callback that will be fired when the patcher receives a chunk from the server. The status string * will contain the current download speed. * \remarks This will be called from the network thread. */ void OnProgressTick(ProgressTickFunc cb); + void RequestGameCode(); void RequestManifest(const plString& mfs); void RequestManifest(const std::vector& mfs); diff --git a/Sources/Plasma/FeatureLib/pfSecurePreloader/CMakeLists.txt b/Sources/Plasma/FeatureLib/pfSecurePreloader/CMakeLists.txt deleted file mode 100644 index aad818e9..00000000 --- a/Sources/Plasma/FeatureLib/pfSecurePreloader/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -include_directories(../../CoreLib) -include_directories(../../NucleusLib) -include_directories(../../NucleusLib/inc) -include_directories(../../PubUtilLib) - -if(WIN32) - add_definitions(-DWIN32) -endif(WIN32) - -set(pfSecurePreloader_SOURCES - pfSecurePreloader.cpp -) - -set(pfSecurePreloader_HEADERS - pfSecurePreloader.h - pfSecurePreloaderCreatable.h -) - -add_library(pfSecurePreloader STATIC ${pfSecurePreloader_SOURCES} ${pfSecurePreloader_HEADERS}) - -source_group("Source Files" FILES ${pfSecurePreloader_SOURCES}) -source_group("Header Files" FILES ${pfSecurePreloader_HEADERS}) diff --git a/Sources/Plasma/FeatureLib/pfSecurePreloader/pfSecurePreloader.cpp b/Sources/Plasma/FeatureLib/pfSecurePreloader/pfSecurePreloader.cpp deleted file mode 100644 index a7e86ec1..00000000 --- a/Sources/Plasma/FeatureLib/pfSecurePreloader/pfSecurePreloader.cpp +++ /dev/null @@ -1,414 +0,0 @@ -/*==LICENSE==* - -CyanWorlds.com Engine - MMOG client, server and tools -Copyright (C) 2011 Cyan Worlds, Inc. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -Additional permissions under GNU GPL version 3 section 7 - -If you modify this Program, or any covered work, by linking or -combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, -NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent -JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK -(or a modified version of those libraries), -containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, -PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG -JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the -licensors of this Program grant you additional -permission to convey the resulting work. Corresponding Source for a -non-source form of such a combination shall include the source code for -the parts of OpenSSL and IJG JPEG Library used as well as that of the covered -work. - -You can contact Cyan Worlds, Inc. by email legal@cyan.com - or by snail mail at: - Cyan Worlds, Inc. - 14617 N Newport Hwy - Mead, WA 99021 - -*==LICENSE==*/ - -#include "pfSecurePreloader.h" - -#include "hsStream.h" -#include "plgDispatch.h" -#include "plCompression/plZlibStream.h" -#include "pnEncryption/plChecksum.h" -#include "plFile/plSecureStream.h" -#include "plFile/plStreamSource.h" -#include "plMessage/plNetCommMsgs.h" -#include "plMessage/plPreloaderMsg.h" -#include "plProgressMgr/plProgressMgr.h" - -bool gSkipPreload = false; -pfSecurePreloader* pfSecurePreloader::fInstance = nil; - -///////////////////////////////////////////////////////////////////// - -typedef std::pair WcharPair; - -struct AuthRequestParams -{ - pfSecurePreloader* fThis; - std::queue fFileGroups; - - AuthRequestParams(pfSecurePreloader* parent) - : fThis(parent) { } -}; - -///////////////////////////////////////////////////////////////////// - -void ProcAuthDownloadParams(AuthRequestParams* params); - -void GotAuthSrvManifest( - ENetError result, - void* param, - const NetCliAuthFileInfo infoArr[], - uint32_t infoCount -) { - AuthRequestParams* arp = (AuthRequestParams*)param; - if (IS_NET_ERROR(result)) - { - FATAL("Failed to get AuthSrv manifest!"); - arp->fThis->Terminate(); - delete arp; - } else { - arp->fThis->PreloadManifest(infoArr, infoCount); - ProcAuthDownloadParams(arp); - } -} - -void GotFileSrvManifest( - ENetError result, - void* param, - const wchar_t group[], - const NetCliFileManifestEntry manifest[], - uint32_t entryCount -) { - pfSecurePreloader* sp = (pfSecurePreloader*)param; - if (result == kNetErrFileNotFound) - { - AuthRequestParams* params = new AuthRequestParams(sp); - params->fFileGroups.push(WcharPair(L"Python", L"pak")); - params->fFileGroups.push(WcharPair(L"SDL", L"sdl")); - ProcAuthDownloadParams(params); - return; - } else if (!entryCount) { - FATAL("SecurePreloader manifest empty!"); - sp->Terminate(); - return; - } - - sp->PreloadManifest(manifest, entryCount); -} - -void FileDownloaded( - ENetError result, - void* param, - const plFileName & filename, - hsStream* writer -) { - pfSecurePreloader* sp = (pfSecurePreloader*)param; - if (IS_NET_ERROR(result)) - { - FATAL("SecurePreloader download failed"); - sp->Terminate(); - } else { - sp->FilePreloaded(filename, writer); - } -} - -void ProcAuthDownloadParams(AuthRequestParams* params) -{ - // Request the "manifests" until there are none left, then download the files - if (params->fFileGroups.empty()) - { - params->fThis->PreloadNextFile(); - delete params; - } else { - WcharPair wp = params->fFileGroups.front(); - params->fFileGroups.pop(); - NetCliAuthFileListRequest(wp.first, wp.second, GotAuthSrvManifest, params); - } -} - -///////////////////////////////////////////////////////////////////// - -class pfSecurePreloaderStream : public plZlibStream -{ - plOperationProgress* fProgress; - bool fIsZipped; - -public: - - pfSecurePreloaderStream(plOperationProgress* prog, bool zipped) - : fProgress(prog), fIsZipped(zipped), plZlibStream() - { - fOutput = new hsRAMStream; - } - - ~pfSecurePreloaderStream() - { - delete fOutput; - fOutput = nil; - plZlibStream::Close(); - } - - bool AtEnd() { return fOutput->AtEnd(); } - uint32_t GetEOF() { return fOutput->GetEOF(); } - uint32_t GetPosition() const { return fOutput->GetPosition(); } - uint32_t GetSizeLeft() const { return fOutput->GetSizeLeft(); } - uint32_t Read(uint32_t count, void* buf) { return fOutput->Read(count, buf); } - void Rewind() { fOutput->Rewind(); } - void SetPosition(uint32_t pos) { fOutput->SetPosition(pos); } - void Skip(uint32_t deltaByteCount) { fOutput->Skip(deltaByteCount); } - - uint32_t Write(uint32_t count, const void* buf) - { - if (fProgress) - fProgress->Increment((float)count); - if (fIsZipped) - return plZlibStream::Write(count, buf); - else - return fOutput->Write(count, buf); - } -}; - -///////////////////////////////////////////////////////////////////// - -hsRAMStream* pfSecurePreloader::LoadToMemory(const plFileName& file) const -{ - if (!plFileInfo(file).Exists()) - return nil; - - hsUNIXStream s; - hsRAMStream* ram = new hsRAMStream; - s.Open(file); - - uint32_t loadLen = 1024 * 1024; - uint8_t* buf = new uint8_t[loadLen]; - while (uint32_t read = s.Read(loadLen, buf)) - ram->Write(read, buf); - delete[] buf; - - s.Close(); - ram->Rewind(); - return ram; -} - -void pfSecurePreloader::SaveFile(hsStream* file, const plFileName& name) const -{ - hsUNIXStream s; - s.Open(name, "wb"); - uint32_t pos = file->GetPosition(); - file->Rewind(); - - uint32_t loadLen = 1024 * 1024; - uint8_t* buf = new uint8_t[loadLen]; - while (uint32_t read = file->Read(loadLen, buf)) - s.Write(read, buf); - file->SetPosition(pos); - s.Close(); - delete[] buf; -} - -bool pfSecurePreloader::IsZipped(const plFileName& filename) const -{ - return filename.GetFileExt().CompareI("gz") == 0; -} - -void pfSecurePreloader::PreloadNextFile() -{ - if (fManifestEntries.empty()) - { - Finish(); - return; - } - - plFileName filename = fDownloadEntries.front(); - hsStream* s = new pfSecurePreloaderStream(fProgress, IsZipped(filename)); - - // Thankfully, both callbacks have the same arguments - if (fLegacyMode) - NetCliAuthFileRequest(filename, s, FileDownloaded, this); - else - NetCliFileDownloadRequest(filename, s, FileDownloaded, this); -} - -void pfSecurePreloader::Init() -{ - if (!fInstance) - fInstance = new pfSecurePreloader; - - fInstance->RegisterAs(kSecurePreloader_KEY); - // TODO: If we're going to support reconnects, then let's do it right. - // Later... - //plgDispatch::Dispatch()->RegisterForExactType(plNetCommAuthConnectedMsg::Index(), fInstance->GetKey()); -} - -void pfSecurePreloader::Start() -{ -#ifndef PLASMA_EXTERNAL_RELEASE - // Finer grained control of the preloader allows us to have synched data but our own python/SDL - // This is useful on outdated/black-box shards like MOULa - if (gSkipPreload) - { - Finish(); - return; - } -#endif - - NetCliAuthGetEncryptionKey(fEncryptionKey, 4); - - // TODO: Localize - fProgress = plProgressMgr::GetInstance()->RegisterOperation(0.0f, "Checking for updates", plProgressMgr::kUpdateText, false, true); - - // Now, we need to fetch the "SecurePreloader" manifest from the file server, which will contain the python and SDL files. - // We're basically reimplementing plResPatcher here, except preferring to keep everything in memory, then flush to disk - // when we're done. If this fails, then we shall download everything from the AuthSrv like in the old days. - NetCliFileManifestRequest(GotFileSrvManifest, this, L"SecurePreloader"); -} - -void pfSecurePreloader::Terminate() -{ - FATAL("pfSecurePreloader failure"); - fProgress->SetAborting(); - - plPreloaderMsg* msg = new plPreloaderMsg; - msg->fSuccess = false; - plgDispatch::Dispatch()->MsgSend(msg); -} - -void pfSecurePreloader::Finish() -{ - plPreloaderMsg* msg = new plPreloaderMsg; - msg->fSuccess = true; - plgDispatch::Dispatch()->MsgSend(msg); -} - -void pfSecurePreloader::Shutdown() -{ - SetInstance(nil); - if (fProgress) - { - delete fProgress; - fProgress = nil; - } - - // Takes care of UnReffing us - UnRegisterAs(kSecurePreloader_KEY); -} - -void pfSecurePreloader::PreloadManifest(const NetCliAuthFileInfo manifestEntries[], uint32_t entryCount) -{ - uint32_t totalBytes = 0; - if (fProgress) - totalBytes = (uint32_t)fProgress->GetMax(); - fLegacyMode = true; - - for (uint32_t i = 0; i < entryCount; ++i) - { - const NetCliAuthFileInfo mfs = manifestEntries[i]; - plFileName filename = plString::FromWchar(mfs.filename); - fDownloadEntries.push(filename); - if (IsZipped(filename)) - fManifestEntries.push(filename.StripFileExt()); - else - fManifestEntries.push(filename); - - totalBytes += mfs.filesize; - } - - if (fProgress) - { - fProgress->SetLength((float)totalBytes); - fProgress->SetTitle("Downloading..."); - } -} - -void pfSecurePreloader::PreloadManifest(const NetCliFileManifestEntry manifestEntries[], uint32_t entryCount) -{ - uint32_t totalBytes = 0; - for (uint32_t i = 0; i < entryCount; ++i) - { - const NetCliFileManifestEntry mfs = manifestEntries[i]; - bool fetchMe = true; - hsRAMStream* s = nil; - plFileName clientName = plString::FromWchar(mfs.clientName); - plFileName downloadName = plString::FromWchar(mfs.downloadName); - - if (plFileInfo(clientName).Exists()) - { - s = LoadToMemory(clientName); - if (s) - { - // Damn this - plMD5Checksum srvHash; - srvHash.SetFromHexString(plString::FromWchar(mfs.md5, 32).c_str()); - - // Now actually copare the hashes - plMD5Checksum lclHash; - lclHash.CalcFromStream(s); - fetchMe = (srvHash != lclHash); - } - } - - if (fetchMe) - { - fManifestEntries.push(clientName); - fDownloadEntries.push(downloadName); - if (IsZipped(downloadName)) - totalBytes += mfs.zipSize; - else - totalBytes += mfs.fileSize; - } else { - plSecureStream* ss = new plSecureStream(s, fEncryptionKey); - plStreamSource::GetInstance()->InsertFile(clientName, ss); - } - - if (s) - delete s; - } - - if (totalBytes && fProgress) - { - fProgress->SetLength((float)totalBytes); - fProgress->SetTitle("Downloading..."); - } - - // This method uses only one manifest, so we're good to go now! - PreloadNextFile(); -} - -void pfSecurePreloader::FilePreloaded(const plFileName& file, hsStream* stream) -{ - // Clear out queue - fDownloadEntries.pop(); - plFileName clientName = fManifestEntries.front(); - fManifestEntries.pop(); - - if (!fLegacyMode) // AuthSrv data caching is useless - { - plFileSystem::CreateDir(clientName.StripFileName(), true); - SaveFile(stream, clientName); - } - - plSecureStream* ss = new plSecureStream(stream, fEncryptionKey); - plStreamSource::GetInstance()->InsertFile(clientName, ss); - delete stream; // SecureStream holds its own decrypted buffer - - // Continue down the warpath - PreloadNextFile(); -} diff --git a/Sources/Plasma/FeatureLib/pfSecurePreloader/pfSecurePreloader.h b/Sources/Plasma/FeatureLib/pfSecurePreloader/pfSecurePreloader.h deleted file mode 100644 index a4660fe4..00000000 --- a/Sources/Plasma/FeatureLib/pfSecurePreloader/pfSecurePreloader.h +++ /dev/null @@ -1,96 +0,0 @@ -/*==LICENSE==* - -CyanWorlds.com Engine - MMOG client, server and tools -Copyright (C) 2011 Cyan Worlds, Inc. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -Additional permissions under GNU GPL version 3 section 7 - -If you modify this Program, or any covered work, by linking or -combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, -NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent -JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK -(or a modified version of those libraries), -containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, -PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG -JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the -licensors of this Program grant you additional -permission to convey the resulting work. Corresponding Source for a -non-source form of such a combination shall include the source code for -the parts of OpenSSL and IJG JPEG Library used as well as that of the covered -work. - -You can contact Cyan Worlds, Inc. by email legal@cyan.com - or by snail mail at: - Cyan Worlds, Inc. - 14617 N Newport Hwy - Mead, WA 99021 - -*==LICENSE==*/ -#ifndef __pfSecurePreloader_h__ -#define __pfSecurePreloader_h__ - -#include "HeadSpin.h" -#include "pnKeyedObject/hsKeyedObject.h" -#include "plNetGameLib/plNetGameLib.h" -#include - -class plOperationProgress; -class hsRAMStream; - -/////////////////////////////////////////////////////////////////////////////// -// pfSecurePreloader - a class for handling files we want downloaded from the -// server into a temporary directory, secured, and deleted on exit. Puts stuff -// into plStreamSource for us -/////////////////////////////////////////////////////////////////////////////// -class pfSecurePreloader : public hsKeyedObject -{ -private: - - static pfSecurePreloader* fInstance; - std::queue fManifestEntries; - std::queue fDownloadEntries; - plOperationProgress* fProgress; - uint32_t fEncryptionKey[4]; - bool fLegacyMode; - - hsRAMStream* LoadToMemory(const plFileName& file) const; - void SaveFile(hsStream* file, const plFileName& name) const; - bool IsZipped(const plFileName& filename) const; - -public: - pfSecurePreloader() : fProgress(nil), fLegacyMode(false) { } - - CLASSNAME_REGISTER(pfSecurePreloader); - GETINTERFACE_ANY(pfSecurePreloader, hsKeyedObject); - - void Init(); - void Start(); - void Terminate(); - void Finish(); - void Shutdown(); - - void PreloadManifest(const NetCliFileManifestEntry manifestEntries[], uint32_t entryCount); - void PreloadManifest(const NetCliAuthFileInfo manifestEntries[], uint32_t entryCount); - void PreloadNextFile(); - void FilePreloaded(const plFileName& filename, hsStream* stream); - - plOperationProgress* GetProgressBar() { return fProgress; } - - static pfSecurePreloader* GetInstance() { return fInstance; } - static void SetInstance(pfSecurePreloader* instance) { fInstance = instance; } -}; - -#endif // __pfSecurePreloader_h__ diff --git a/Sources/Plasma/FeatureLib/pfSecurePreloader/pfSecurePreloaderCreatable.h b/Sources/Plasma/FeatureLib/pfSecurePreloader/pfSecurePreloaderCreatable.h deleted file mode 100644 index ee2e0209..00000000 --- a/Sources/Plasma/FeatureLib/pfSecurePreloader/pfSecurePreloaderCreatable.h +++ /dev/null @@ -1,57 +0,0 @@ -/*==LICENSE==* - -CyanWorlds.com Engine - MMOG client, server and tools -Copyright (C) 2011 Cyan Worlds, Inc. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -Additional permissions under GNU GPL version 3 section 7 - -If you modify this Program, or any covered work, by linking or -combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, -NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent -JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK -(or a modified version of those libraries), -containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, -PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG -JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the -licensors of this Program grant you additional -permission to convey the resulting work. Corresponding Source for a -non-source form of such a combination shall include the source code for -the parts of OpenSSL and IJG JPEG Library used as well as that of the covered -work. - -You can contact Cyan Worlds, Inc. by email legal@cyan.com - or by snail mail at: - Cyan Worlds, Inc. - 14617 N Newport Hwy - Mead, WA 99021 - -*==LICENSE==*/ -/***************************************************************************** -* -* $/Plasma20/Sources/Plasma/FeatureLib/pfSecurePreloader/pfSecurePreloaderCreatable.h -* -***/ - -#ifndef PLASMA20_SOURCES_PLASMA_FEATURELIB_PFSECUREPRELOADER_PFSECUREPRELOADERCREATABLE_H -#define PLASMA20_SOURCES_PLASMA_FEATURELIB_PFSECUREPRELOADER_PFSECUREPRELOADERCREATABLE_H - -#include "pnFactory/plCreator.h" - -#include "pfSecurePreloader.h" -REGISTER_NONCREATABLE(pfSecurePreloader); - - -#endif // PLASMA20_SOURCES_PLASMA_FEATURELIB_PFSECUREPRELOADER_PFSECUREPRELOADERCREATABLE_H diff --git a/Sources/Plasma/NucleusLib/inc/plCreatableIndex.h b/Sources/Plasma/NucleusLib/inc/plCreatableIndex.h index 262da7fe..a185eedc 100644 --- a/Sources/Plasma/NucleusLib/inc/plCreatableIndex.h +++ b/Sources/Plasma/NucleusLib/inc/plCreatableIndex.h @@ -84,7 +84,7 @@ CLASS_INDEX_LIST_START CLASS_INDEX(plModifier), CLASS_INDEX(plSingleModifier), CLASS_INDEX(plSimpleModifier), - CLASS_INDEX(pfSecurePreloader), + CLASS_INDEX(UNUSED_pfSecurePreloader), CLASS_INDEX(UNUSED_plRandomTMModifier), CLASS_INDEX(plInterestingModifier), CLASS_INDEX(plDetectorModifier), @@ -725,7 +725,7 @@ CLASS_INDEX_LIST_START CLASS_INDEX(plAvBrainDrive), CLASS_INDEX(plAvBrainSample), CLASS_INDEX(plAvBrainGeneric), - CLASS_INDEX(plPreloaderMsg), + CLASS_INDEX(UNUSED_plPreloaderMsg), CLASS_INDEX(plAvBrainLadder), CLASS_INDEX(plInputIfaceMgrMsg), CLASS_INDEX(pfKIMsg), diff --git a/Sources/Plasma/NucleusLib/pnKeyedObject/plFixedKey.cpp b/Sources/Plasma/NucleusLib/pnKeyedObject/plFixedKey.cpp index b0b0d5ce..f01895c2 100644 --- a/Sources/Plasma/NucleusLib/pnKeyedObject/plFixedKey.cpp +++ b/Sources/Plasma/NucleusLib/pnKeyedObject/plFixedKey.cpp @@ -118,8 +118,6 @@ plKeySeed SeedList[] = { { kJournalBookMgr_KEY, CLASS_INDEX_SCOPED( pfJournalBook ), "kJournalBookMgr_KEY", }, { kAgeLoader_KEY, CLASS_INDEX_SCOPED( plAgeLoader), "kAgeLoader_KEY", }, { kBuiltIn3rdPersonCamera_KEY, CLASS_INDEX_SCOPED( plCameraModifier1 ), "kBuiltIn3rdPersonCamera_KEY", }, - { kSecurePreloader_KEY, CLASS_INDEX_SCOPED( pfSecurePreloader ), "kSecurePreloader_KEY", }, - { kLast_Fixed_KEY, CLASS_INDEX_SCOPED( plSceneObject ), "kLast_Fixed_KEY", } }; diff --git a/Sources/Plasma/NucleusLib/pnKeyedObject/plFixedKey.h b/Sources/Plasma/NucleusLib/pnKeyedObject/plFixedKey.h index 31fa53ac..0e2cbc2b 100644 --- a/Sources/Plasma/NucleusLib/pnKeyedObject/plFixedKey.h +++ b/Sources/Plasma/NucleusLib/pnKeyedObject/plFixedKey.h @@ -85,7 +85,6 @@ enum plFixedKeyId kJournalBookMgr_KEY, kAgeLoader_KEY, kBuiltIn3rdPersonCamera_KEY, - kSecurePreloader_KEY, kLast_Fixed_KEY }; diff --git a/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.cpp b/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.cpp index a0139533..b3366867 100644 --- a/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.cpp +++ b/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.cpp @@ -45,12 +45,16 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plgDispatch.h" #include "plAgeLoader/plAgeLoader.h" +#include "plFile/plEncryptedStream.h" +#include "plFile/plStreamSource.h" +#include "plFile/plSecureStream.h" #include "plMessage/plResPatcherMsg.h" #include "pfPatcher/pfPatcher.h" #include "plProgressMgr/plProgressMgr.h" #include "plResMgr/plResManager.h" extern bool gDataServerLocal; +bool gSkipPreload = false; ///////////////////////////////////////////////////////////////////////////// @@ -98,6 +102,21 @@ void plResPatcher::OnFileDownloaded(const plFileName& file) } } +bool plResPatcher::OnGameCodeDiscovered(const plFileName& file, hsStream* stream) +{ + plSecureStream* ss = new plSecureStream(false, plStreamSource::GetInstance()->GetEncryptionKey()); + if (ss->Open(stream)) { + plStreamSource::GetInstance()->InsertFile(file, ss); + + // SecureStream will hold a decrypted buffer... + stream->Close(); + delete stream; + } else + plStreamSource::GetInstance()->InsertFile(file, stream); + + return true; // ASSume success for now... +} + void plResPatcher::OnProgressTick(uint64_t dl, uint64_t total, const plString& msg) { if (dl && total) { @@ -121,6 +140,14 @@ pfPatcher* plResPatcher::CreatePatcher() patcher->OnFileDownloadBegin(std::bind(&plResPatcher::OnFileDownloadBegin, this, std::placeholders::_1)); patcher->OnFileDownloaded(std::bind(&plResPatcher::OnFileDownloaded, this, std::placeholders::_1)); patcher->OnProgressTick(std::bind(&plResPatcher::OnProgressTick, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + + // sneaky hax: do the old SecurePreloader thing.... except here + if (!fRequestedGameCode && !gSkipPreload) { + patcher->OnGameCodeDiscovery(std::bind(&plResPatcher::OnGameCodeDiscovered, this, std::placeholders::_1, std::placeholders::_2)); + patcher->RequestGameCode(); + fRequestedGameCode = true; + } + return patcher; } @@ -133,7 +160,7 @@ void plResPatcher::InitProgress() ///////////////////////////////////////////////////////////////////////////// plResPatcher::plResPatcher() - : fProgress(nullptr) { } + : fProgress(nullptr), fRequestedGameCode(false) { } plResPatcher::~plResPatcher() { diff --git a/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.h b/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.h index 8987fbb0..ee29e962 100644 --- a/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.h +++ b/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.h @@ -58,12 +58,14 @@ class plResPatcher { plOperationProgress* fProgress; static plResPatcher* fInstance; + bool fRequestedGameCode; friend class plAgeLoader; void OnCompletion(ENetError, const plString& msg); void OnFileDownloadBegin(const plFileName& file); void OnFileDownloaded(const plFileName& file); + bool OnGameCodeDiscovered(const plFileName& file, class hsStream* stream); void OnProgressTick(uint64_t dl, uint64_t total, const plString& msg); class pfPatcher* CreatePatcher(); diff --git a/Sources/Plasma/PubUtilLib/plFile/plSecureStream.cpp b/Sources/Plasma/PubUtilLib/plFile/plSecureStream.cpp index 87bf0f15..391bb807 100644 --- a/Sources/Plasma/PubUtilLib/plFile/plSecureStream.cpp +++ b/Sources/Plasma/PubUtilLib/plFile/plSecureStream.cpp @@ -667,17 +667,13 @@ bool plSecureStream::IsSecureFile(const plFileName& fileName) hsStream* plSecureStream::OpenSecureFile(const plFileName& fileName, const uint32_t flags /* = kRequireEncryption */, uint32_t* key /* = nil */) { bool requireEncryption = flags & kRequireEncryption; -#ifndef PLASMA_EXTERNAL_RELEASE - requireEncryption = false; -#endif - bool deleteOnExit = flags & kDeleteOnExit; bool isEncrypted = IsSecureFile(fileName); - hsStream* s = nil; + hsStream* s = nullptr; if (isEncrypted) s = new plSecureStream(deleteOnExit, key); - else if (!requireEncryption) // If this isn't an external release, let them use unencrypted data + else if (!requireEncryption) s = new hsUNIXStream; if (s) diff --git a/Sources/Plasma/PubUtilLib/plFile/plStreamSource.cpp b/Sources/Plasma/PubUtilLib/plFile/plStreamSource.cpp index ba8b145a..cba9a979 100644 --- a/Sources/Plasma/PubUtilLib/plFile/plStreamSource.cpp +++ b/Sources/Plasma/PubUtilLib/plFile/plStreamSource.cpp @@ -40,7 +40,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com *==LICENSE==*/ -#include +#include "HeadSpin.h" #include "plStreamSource.h" #include "plSecureStream.h" #include "plEncryptedStream.h" @@ -49,8 +49,15 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com # include #endif +plStreamSource::plStreamSource() +{ + memset(fServerKey, 0, arrsize(fServerKey)); +} + void plStreamSource::ICleanup() { + hsTempMutexLock lock(fMutex); + // loop through all the file data records, and delete the streams decltype(fFileData.begin()) curData; for (curData = fFileData.begin(); curData != fFileData.end(); curData++) @@ -65,6 +72,8 @@ void plStreamSource::ICleanup() hsStream* plStreamSource::GetFile(const plFileName& filename) { + hsTempMutexLock lock(fMutex); + plFileName sFilename = filename.Normalize('/'); if (fFileData.find(sFilename) == fFileData.end()) { @@ -78,14 +87,15 @@ hsStream* plStreamSource::GetFile(const plFileName& filename) fFileData[sFilename].fExt = sFilename.GetFileExt(); if (plSecureStream::IsSecureFile(filename)) { - uint32_t encryptionKey[4]; - if (!plSecureStream::GetSecureEncryptionKey(filename, encryptionKey, 4)) - { - FATAL("Hey camper... You need an NTD key file!"); - return nil; - } + hsStream* ss = nullptr; - fFileData[sFilename].fStream = plSecureStream::OpenSecureFile(filename, 0, encryptionKey); + uint32_t encryptionKey[4]; + if (plSecureStream::GetSecureEncryptionKey(filename, encryptionKey, 4)) + ss = plSecureStream::OpenSecureFile(filename, 0, encryptionKey); + else + ss = plSecureStream::OpenSecureFile(filename, 0, fServerKey); + fFileData[sFilename].fStream = ss; + hsAssert(ss, "failed to open a SecureStream for a disc file!"); } else // otherwise it is an encrypted or plain stream, this call handles both fFileData[sFilename].fStream = plEncryptedStream::OpenEncryptedFile(filename); @@ -102,6 +112,7 @@ std::vector plStreamSource::GetListOfNames(const plFileName& dir, co { plFileName sDir = dir.Normalize('/'); hsAssert(ext.CharAt(0) != '.', "Don't add a dot"); + hsTempMutexLock lock(fMutex); // loop through all the file data records, and create the list std::vector retVal; @@ -131,6 +142,7 @@ bool plStreamSource::InsertFile(const plFileName& filename, hsStream* stream) { plFileName sFilename = filename.Normalize('/'); + hsTempMutexLock lock(fMutex); if (fFileData.find(sFilename) != fFileData.end()) return false; // duplicate entry, return failure diff --git a/Sources/Plasma/PubUtilLib/plFile/plStreamSource.h b/Sources/Plasma/PubUtilLib/plFile/plStreamSource.h index a565ad95..f9b3908c 100644 --- a/Sources/Plasma/PubUtilLib/plFile/plStreamSource.h +++ b/Sources/Plasma/PubUtilLib/plFile/plStreamSource.h @@ -43,8 +43,8 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #define plStreamSource_h_inc #include -#include #include "hsStream.h" +#include "hsThread.h" // A class for holding and accessing file streams. The preloader will insert // files in here once they are loaded. In internal builds, if a requested file @@ -60,10 +60,12 @@ private: hsStream* fStream; // we own this pointer, so clean it up }; std::map fFileData; // key is filename + hsMutex fMutex; + uint32_t fServerKey[4]; void ICleanup(); // closes all file pointers and cleans up after itself - plStreamSource() {} + plStreamSource(); public: ~plStreamSource() {ICleanup();} @@ -77,6 +79,9 @@ public: // For other classes to insert files (takes ownership of the stream if successful) bool InsertFile(const plFileName& filename, hsStream* stream); + /** Gets a pointer to our encryption key */ + uint32_t* GetEncryptionKey() { return fServerKey; } + // Instance handling static plStreamSource* GetInstance(); }; diff --git a/Sources/Plasma/PubUtilLib/plMessage/CMakeLists.txt b/Sources/Plasma/PubUtilLib/plMessage/CMakeLists.txt index 8caa137c..077f347f 100644 --- a/Sources/Plasma/PubUtilLib/plMessage/CMakeLists.txt +++ b/Sources/Plasma/PubUtilLib/plMessage/CMakeLists.txt @@ -98,7 +98,6 @@ set(plMessage_HEADERS plOneShotMsg.h plParticleUpdateMsg.h plPickedMsg.h - plPreloaderMsg.h plRenderMsg.h plRenderRequestMsg.h plReplaceGeometryMsg.h diff --git a/Sources/Plasma/PubUtilLib/plMessage/plMessageCreatable.h b/Sources/Plasma/PubUtilLib/plMessage/plMessageCreatable.h index 906e050c..812f998a 100644 --- a/Sources/Plasma/PubUtilLib/plMessage/plMessageCreatable.h +++ b/Sources/Plasma/PubUtilLib/plMessage/plMessageCreatable.h @@ -319,9 +319,6 @@ REGISTER_CREATABLE(plNetCommPublicAgeListMsg); REGISTER_CREATABLE(plNetCommPublicAgeMsg); REGISTER_CREATABLE(plNetCommRegisterAgeMsg); -#include "plPreloaderMsg.h" -REGISTER_CREATABLE(plPreloaderMsg); - #include "plNetClientMgrMsg.h" REGISTER_CREATABLE(plNetClientMgrMsg); diff --git a/Sources/Plasma/PubUtilLib/plMessage/plPreloaderMsg.h b/Sources/Plasma/PubUtilLib/plMessage/plPreloaderMsg.h deleted file mode 100644 index 3cf88dd8..00000000 --- a/Sources/Plasma/PubUtilLib/plMessage/plPreloaderMsg.h +++ /dev/null @@ -1,67 +0,0 @@ -/*==LICENSE==* - -CyanWorlds.com Engine - MMOG client, server and tools -Copyright (C) 2011 Cyan Worlds, Inc. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -Additional permissions under GNU GPL version 3 section 7 - -If you modify this Program, or any covered work, by linking or -combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, -NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent -JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK -(or a modified version of those libraries), -containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, -PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG -JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the -licensors of this Program grant you additional -permission to convey the resulting work. Corresponding Source for a -non-source form of such a combination shall include the source code for -the parts of OpenSSL and IJG JPEG Library used as well as that of the covered -work. - -You can contact Cyan Worlds, Inc. by email legal@cyan.com - or by snail mail at: - Cyan Worlds, Inc. - 14617 N Newport Hwy - Mead, WA 99021 - -*==LICENSE==*/ -/***************************************************************************** -* -* $/Plasma20/Sources/Plasma/PubUtilLib/plMessage/plPreloaderMsg.h -* -***/ - -#ifndef PLASMA20_SOURCES_PLASMA_PUBUTILLIB_PLMESSAGE_PLPRELOADERMSG_H -#define PLASMA20_SOURCES_PLASMA_PUBUTILLIB_PLMESSAGE_PLPRELOADERMSG_H - -#include "pnMessage/plMessage.h" - -class plPreloaderMsg : public plMessage { -public: - bool fSuccess; - - plPreloaderMsg () { SetBCastFlag(kBCastByExactType); } - - CLASSNAME_REGISTER(plPreloaderMsg); - GETINTERFACE_ANY(plPreloaderMsg, plMessage); - - void Read (hsStream* stream, hsResMgr* ) { FATAL("plPreloaderMsg::Read"); } - void Write (hsStream* stream, hsResMgr* ) { FATAL("plPreloaderMsg::Write"); } -}; - - -#endif // PLASMA20_SOURCES_PLASMA_PUBUTILLIB_PLMESSAGE_PLPRELOADERMSG_H diff --git a/Sources/Plasma/PubUtilLib/plNetClientComm/plNetClientComm.cpp b/Sources/Plasma/PubUtilLib/plNetClientComm/plNetClientComm.cpp index 4db84e39..58094b1e 100644 --- a/Sources/Plasma/PubUtilLib/plNetClientComm/plNetClientComm.cpp +++ b/Sources/Plasma/PubUtilLib/plNetClientComm/plNetClientComm.cpp @@ -60,6 +60,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plVault/plVault.h" #include "plMessage/plAccountUpdateMsg.h" #include "plNetClient/plNetClientMgr.h" +#include "plFile/plStreamSource.h" #include "pfMessage/pfKIMsg.h" @@ -414,6 +415,9 @@ static void INetCliAuthLoginRequestCallback ( if (!wantsStartUpAge && 0 == StrCmpI(s_players[i].playerName, s_iniStartupPlayerName, (unsigned)-1)) s_player = &s_players[i]; } + + // store this server's encryption key for posterity + NetCliAuthGetEncryptionKey(plStreamSource::GetInstance()->GetEncryptionKey(), 4); } else s_account.accountUuid = kNilUuid; diff --git a/Sources/Tools/MaxMain/CMakeLists.txt b/Sources/Tools/MaxMain/CMakeLists.txt index 0df9965a..71b2ec93 100644 --- a/Sources/Tools/MaxMain/CMakeLists.txt +++ b/Sources/Tools/MaxMain/CMakeLists.txt @@ -124,7 +124,6 @@ target_link_libraries(MaxMain pfJournalBook) target_link_libraries(MaxMain pfLocalizationMgr) target_link_libraries(MaxMain pfMessage) target_link_libraries(MaxMain pfPython) -target_link_libraries(MaxMain pfSecurePreloader) target_link_libraries(MaxMain pfSurface) target_link_libraries(MaxMain plAgeDescription) target_link_libraries(MaxMain plAgeLoader) diff --git a/Sources/Tools/MaxPlasmaLights/CMakeLists.txt b/Sources/Tools/MaxPlasmaLights/CMakeLists.txt index cbb6402d..1a890d1b 100644 --- a/Sources/Tools/MaxPlasmaLights/CMakeLists.txt +++ b/Sources/Tools/MaxPlasmaLights/CMakeLists.txt @@ -57,7 +57,6 @@ target_link_libraries(MaxPlasmaLights pfJournalBook) target_link_libraries(MaxPlasmaLights pfLocalizationMgr) target_link_libraries(MaxPlasmaLights pfMessage) target_link_libraries(MaxPlasmaLights pfPython) -target_link_libraries(MaxPlasmaLights pfSecurePreloader) target_link_libraries(MaxPlasmaLights pfSurface) target_link_libraries(MaxPlasmaLights plAgeDescription) target_link_libraries(MaxPlasmaLights plAgeLoader)