Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Native Branch: Add CMD_XFER_ACCEPT support #2691

Merged
merged 37 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
3689aaa
Make m_ServiceStatus volatile
0blu Jun 18, 2024
8355cda
Add type size to eAuthCmd and AuthResult
0blu Jun 18, 2024
92cd000
NativeIO: Realmd: First impl of `LogonChallenge` just like cMangos
0blu Jun 19, 2024
77dd187
Add "Network" to log type string
0blu Jun 22, 2024
6fe57b4
Make m_ServiceStatus volatile (again)
0blu Jun 22, 2024
32716c6
SRP6 add const to parameter
0blu Jun 22, 2024
3f2427f
Database add DbExecMode to force sync statements (prevent race condit…
0blu Jun 22, 2024
6e8f563
Reimplement most AuthSocket handers async (like cMangos)
0blu Jun 22, 2024
67102f9
Use high performance winsock2 async sockets
0blu Jun 22, 2024
13e2fc6
Async networking: Split declaration and definition inside header
0blu Jun 22, 2024
c59ae3b
Async networking: Move implementation into own folder
0blu Jun 22, 2024
552ad6e
Fix ATTR_PRINTF on PExecute with DbExecMode
0blu Jun 22, 2024
e803d69
Add function IO::Multithreading::CreateThread with nameable threads
0blu Jun 22, 2024
24db2b2
Add IO::Timer::AsyncSystemTimer
0blu Jun 23, 2024
74cff36
Change RunEventLoop error handling
0blu Jun 23, 2024
e5ea516
Merge branch 'native' of https://github.com/vmangos/core into native
0blu Jun 23, 2024
ddac80c
Remove Timer was already removed error log
0blu Jun 23, 2024
4c97168
Add comment explaining why we cant use `SetThreadDescription`
0blu Jun 23, 2024
71ef40c
Remove `MaNGOS::` prefix from `IO::` namespace
0blu Jun 23, 2024
6c8ad69
Add TrinityCore's EnumFlag implementation
0blu Jun 23, 2024
05f912c
Fix windows #include
0blu Jun 23, 2024
148e395
Please split `socket->Write(...)` calls
0blu Jun 24, 2024
c503c03
Async socket add Write for `uint8[]`
0blu Jun 24, 2024
6cf961e
Update AsyncServerListener.h
0blu Jun 24, 2024
90b6911
Update AuthCodes.h
0blu Jun 24, 2024
ff70719
Add namespace `IO::Filesystem`
0blu Jun 24, 2024
1286ead
ByteBuffer add `append(std::vector<uint8> const& src)`
0blu Jun 24, 2024
7fdcc4d
Realmd: Remove old PatchHandler
0blu Jun 24, 2024
5daa4fe
Add new `ClientPatchCache`
0blu Jun 24, 2024
16dc5d8
Realmd: Add support for `CMD_XFER_ACCEPT`
0blu Jun 24, 2024
b07e7e7
Merge branch 'native' of https://github.com/vmangos/core into native
0blu Jun 24, 2024
1dc90ee
Remove ACE_TYPES from `XFER_DATA_CHUNK`
0blu Jun 24, 2024
c472240
Add `IO::Networking::` `IpAddress` and `IpEndpoint` structures
0blu Jun 24, 2024
13ed373
Add `IO::Networking::IsInSameSubnet`
0blu Jun 25, 2024
124d3d2
Add function `AsyncSocket<T>::GetRemoteEndpoint()` and `GetRemoteIpSt…
0blu Jun 25, 2024
d9054c1
Make ReamList use new `IO::Networking::IpAddress`
0blu Jun 25, 2024
f2d94b9
Fix `IO::Filesystem::GetAllFilesInFolder` comment
0blu Jun 25, 2024
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
3 changes: 1 addition & 2 deletions src/realmd/AuthCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ enum eAuthCmd : uint8
CMD_REALM_LIST = 0x10,
CMD_XFER_INITIATE = 0x30,
CMD_XFER_DATA = 0x31,
// these opcodes no longer exist in currently supported client
CMD_XFER_ACCEPT = 0x32,
CMD_XFER_RESUME = 0x33,
CMD_XFER_CANCEL = 0x34
CMD_XFER_CANCEL = 0x34,
};

// not used by us currently
Expand Down
242 changes: 115 additions & 127 deletions src/realmd/AuthSocket.cpp

Large diffs are not rendered by default.

19 changes: 11 additions & 8 deletions src/realmd/AuthSocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "ByteBuffer.h"
#include "IO/Networking/AsyncSocket.h"
#include "IO/Timer/TimerHandle.h"
#include "IO/Filesystem/FileHandle.h"

struct PINData
{
Expand Down Expand Up @@ -77,11 +78,11 @@ class AuthSocket : public IO::Networking::AsyncSocket<AuthSocket>
void _HandleReconnectChallenge();
void _HandleReconnectProof();
void _HandleRealmList();
//data transfer handle for patch

bool _HandleXferResume();
bool _HandleXferCancel();
bool _HandleXferAccept();
//data transfer handle for patch
void _HandleXferAccept();
void _HandleXferResume();
void _HandleXferCancel();

private:
enum eStatus
Expand All @@ -95,7 +96,6 @@ class AuthSocket : public IO::Networking::AsyncSocket<AuthSocket>
};

bool VerifyVersion(uint8 const* a, int32 aLength, uint8 const* versionProof, bool isReconnect);
std::string GetRealmAddress(Realm const& realm) const;

SRP6 srp;
BigNumber m_reconnectProof;
Expand Down Expand Up @@ -139,11 +139,14 @@ class AuthSocket : public IO::Networking::AsyncSocket<AuthSocket>
typedef std::map<uint32, AccountTypes> AccountSecurityMap;
AccountSecurityMap m_accountSecurityOnRealm;

ACE_HANDLE m_patch = ACE_INVALID_HANDLE;
// Auto kick realmd client connection after some time
std::shared_ptr<IO::Timer::TimerHandle> m_sessionDurationTimeout;

void InitPatch();
// Patching stuff
void InitAndHandOverControlToPatchHandler();
std::unique_ptr<IO::Filesystem::FileHandleReadonly> m_pendingPatchFile = nullptr;

std::shared_ptr<IO::Timer::TimerHandle> m_sessionDurationTimeout;
void RepeatInternalXferLoop(std::shared_ptr<uint8_t[]> rawChunk);
};

#endif
Expand Down
8 changes: 4 additions & 4 deletions src/realmd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

set(EXECUTABLE_NAME realmd)
set(EXECUTABLE_SRCS
set(EXECUTABLE_SRCS
AuthCodes.h
AuthSocket.h
PatchHandler.h
RealmList.h
AuthSocket.cpp
Main.cpp
PatchHandler.cpp
RealmList.cpp
ClientPatchCache.h
ClientPatchCache.cpp
Main.cpp
)


Expand Down
94 changes: 94 additions & 0 deletions src/realmd/ClientPatchCache.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#include "./ClientPatchCache.h"
#include "Policies/SingletonImp.h"
#include "Log.h"
#include "md5.h"
#include "Config/Config.h"
#include "IO/Filesystem/FileSystem.h"
#include "IO/Filesystem/FileHandle.h"

INSTANTIATE_SINGLETON_1(ClientPatchCache);

ClientPatchCache::ClientPatchCache()
{
LoadPatchesInfo();
}

void ClientPatchCache::LoadPatchesInfo()
{
std::string folderPath = sConfig.GetStringDefault("PatchesDir", "./patches") + "/";
std::string fullFolderPath = IO::Filesystem::ToAbsolutePath(folderPath);

sLog.Out(LOG_BASIC, LOG_LVL_DEBUG, "[PatchCache] Loading available game client patches from folder %s", fullFolderPath.c_str());

for (const std::string& filePath : IO::Filesystem::GetAllFilesInFolder(fullFolderPath, IO::Filesystem::OutputFilePath::FullFilePath))
{
auto fileHandle = IO::Filesystem::TryOpenFileReadonly(filePath, IO::Filesystem::FileOpenFlags::HintSequentialRead);
if (fileHandle)
{
sLog.Out(LOG_BASIC, LOG_LVL_DEBUG, "[PatchCache] Calculate hash of %s", filePath.c_str());
CalculateAndCacheHash(std::move(fileHandle));
}
else
{
sLog.Out(LOG_BASIC, LOG_LVL_ERROR, "[PatchCache] Failed to open %s", filePath.c_str());
}
}
}

Md5HashDigest ClientPatchCache::GetOrCalculateHash(std::unique_ptr<IO::Filesystem::FileHandleReadonly> const& fileHandle)
{
auto filePath = fileHandle->GetAbsoluteFilePath();
auto lastModifyDate = fileHandle->GetLastModifyDate();
auto fileSize = fileHandle->GetTotalFileSize();

m_knownPatches_mutex.lock_shared();
auto const& exisingEntry = m_knownPatches.find(filePath);
if (exisingEntry == m_knownPatches.end() || exisingEntry->second.lastModifyDate != lastModifyDate || exisingEntry->second.fileSize != fileSize)
{ // file does not exist in cache or was changed
m_knownPatches_mutex.unlock_shared();
sLog.Out(LOG_BASIC, LOG_LVL_BASIC, "[PatchCache] Detected change of file '%s'. Will recalculate hash.", filePath.c_str());
// It's important to have a duplicate file handle here, since we want to guarantee easy access
return CalculateAndCacheHash(fileHandle->DuplicateFileHandle());
}
else
{ // we can use the existent entry
Md5HashDigest md5Hash = exisingEntry->second.md5Hash;
m_knownPatches_mutex.unlock_shared();
return md5Hash;
}
}

Md5HashDigest ClientPatchCache::CalculateAndCacheHash(std::unique_ptr<IO::Filesystem::FileHandleReadonly> fileHandle)
{
MD5_CTX ctx;
MD5_Init(&ctx);

size_t constexpr CHECK_CHUNK_SIZE = 1024 * 1024; // 1 MiB Chunks
std::vector<uint8_t> buffer(CHECK_CHUNK_SIZE);

uint64_t totalRead = 0;

do { // Read the file chunk by chunk and add insert it into our MD5_Update
uint64_t actuallyRead = fileHandle->ReadSync(buffer.data(), CHECK_CHUNK_SIZE);
MD5_Update(&ctx, buffer.data(), (size_t) actuallyRead);

totalRead += actuallyRead;

if (actuallyRead < CHECK_CHUNK_SIZE)
break; // we read less than expected, meaning the file is done
} while (true);

PatchCacheEntry entry;
entry.filePath = fileHandle->GetAbsoluteFilePath();
entry.lastModifyDate = fileHandle->GetLastModifyDate();
entry.fileSize = fileHandle->GetTotalFileSize();
MD5_Final(entry.md5Hash.digest.data(), &ctx);

MANGOS_ASSERT(totalRead == entry.fileSize);

m_knownPatches_mutex.lock();
m_knownPatches.emplace(entry.filePath, entry);
m_knownPatches_mutex.unlock();

return entry.md5Hash;
}
51 changes: 51 additions & 0 deletions src/realmd/ClientPatchCache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#ifndef MANGOS_CLIENTPATCHCACHE_H
#define MANGOS_CLIENTPATCHCACHE_H

#include <mutex>
#include <shared_mutex>
#include <array>
#include <memory>
#include <unordered_map>
#include <chrono>

#include "IO/Filesystem/FileHandle.h"
#include "Policies/Singleton.h"

struct Md5HashDigest
{
std::array<uint8_t, 16> digest;
};

struct PatchCacheEntry
{
// To figure out if the file was changed
std::string filePath;
uint64_t fileSize;
std::chrono::system_clock::time_point lastModifyDate;

// The stuff we are actually interested in
Md5HashDigest md5Hash;
};

/// Caches MD5 hash of client patches present on the server
class ClientPatchCache : public MaNGOS::Singleton<ClientPatchCache, MaNGOS::ClassLevelLockable<ClientPatchCache, std::mutex>>
{
public:
explicit ClientPatchCache();

/// This function will detect changes in the size or modification date of the file
/// The FileHandle will be untouched (You can use the same handle to send the data to the client)
Md5HashDigest GetOrCalculateHash(std::unique_ptr<IO::Filesystem::FileHandleReadonly> const& fileHandle);

/// The FileHandle will be taken over and freed
Md5HashDigest CalculateAndCacheHash(std::unique_ptr<IO::Filesystem::FileHandleReadonly> fileHandle);

private:
void LoadPatchesInfo();
std::shared_mutex m_knownPatches_mutex; // will be read-lock when normal access, will be write-lock when adding a new entry
std::unordered_map<std::string /*filePath*/, PatchCacheEntry> m_knownPatches;
};

#define sRealmdPatchCache MaNGOS::Singleton<ClientPatchCache>::Instance()

#endif //MANGOS_CLIENTPATCHCACHE_H
3 changes: 3 additions & 0 deletions src/realmd/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "Common.h"
#include "Database/DatabaseEnv.h"
#include "RealmList.h"
#include "ClientPatchCache.h"

#include "Config/Config.h"
#include "Log.h"
Expand Down Expand Up @@ -270,6 +271,8 @@ extern int main(int argc, char **argv)
return 1;
}

(void) sRealmdPatchCache; // <-- This will initialize the singleton. Which will preload all known patches.

// cleanup query
// set expired bans to inactive
LoginDatabase.BeginTransaction();
Expand Down
Loading
Loading