[9935] ACE realmd, thanks to Zor and Vladimir for windows.

This commit is contained in:
Derex 2010-05-19 23:36:08 +03:00
parent d4f1b510ae
commit 8a1fd9e086
13 changed files with 835 additions and 338 deletions

194
src/realmd/PatchHandler.cpp Normal file
View file

@ -0,0 +1,194 @@
#include "PatchHandler.h"
#include "AuthCodes.h"
#include "Log.h"
#include "Common.h"
#include <ace/OS_NS_sys_socket.h>
#include <ace/OS_NS_dirent.h>
#include <ace/OS_NS_errno.h>
#include <ace/OS_NS_unistd.h>
#include <ace/os_include/netinet/os_tcp.h>
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif
#if defined( __GNUC__ )
#pragma pack(1)
#else
#pragma pack(push,1)
#endif
struct Chunk
{
ACE_UINT8 cmd;
ACE_UINT16 data_size;
ACE_UINT8 data[4096]; // 4096 - page size on most arch
};
#if defined( __GNUC__ )
#pragma pack()
#else
#pragma pack(pop)
#endif
PatchHandler::PatchHandler(ACE_HANDLE socket, ACE_HANDLE patch)
{
reactor(NULL);
set_handle(socket);
patch_fd_ = patch;
}
PatchHandler::~PatchHandler()
{
if(patch_fd_ != ACE_INVALID_HANDLE)
ACE_OS::close(patch_fd_);
}
int PatchHandler::open(void*)
{
if(get_handle() == ACE_INVALID_HANDLE || patch_fd_ == ACE_INVALID_HANDLE)
return -1;
int nodelay = 0;
if (-1 == peer().set_option(ACE_IPPROTO_TCP,
TCP_NODELAY,
&nodelay,
sizeof(nodelay)))
{
return -1;
}
#if defined(TCP_CORK)
int cork = 1;
if (-1 == peer().set_option(ACE_IPPROTO_TCP,
TCP_CORK,
&cork,
sizeof(cork)))
{
return -1;
}
#endif //TCP_CORK
(void) peer().disable(ACE_NONBLOCK);
return activate(THR_NEW_LWP | THR_DETACHED | THR_INHERIT_SCHED);
}
int PatchHandler::svc(void)
{
// Do 1 second sleep, similar to the one in game/WorldSocket.cpp
// Seems client have problems with too fast sends.
ACE_OS::sleep(1);
int flags = MSG_NOSIGNAL;
Chunk data;
data.cmd = XFER_DATA;
ssize_t r;
while((r = ACE_OS::read(patch_fd_, data.data, sizeof(data.data))) > 0)
{
data.data_size = (ACE_UINT16)r;
if(peer().send((const char*)&data,
((size_t) r) + sizeof(data) - sizeof(data.data),
flags) == -1)
{
return -1;
}
}
if(r == -1)
{
return -1;
}
return 0;
}
PatchCache::~PatchCache()
{
for (Patches::iterator i = patches_.begin (); i != patches_.end (); i++)
delete i->second;
}
PatchCache::PatchCache()
{
LoadPatchesInfo();
}
PatchCache* PatchCache::instance()
{
return ACE_Singleton<PatchCache, ACE_Thread_Mutex>::instance();
}
void PatchCache::LoadPatchMD5(const char* szFileName)
{
// Try to open the patch file
std::string path = "./patches/";
path += szFileName;
FILE * pPatch = fopen(path.c_str (), "rb");
sLog.outDebug("Loading patch info from %s", path.c_str());
if(!pPatch)
return;
// Calculate the MD5 hash
MD5_CTX ctx;
MD5_Init(&ctx);
const size_t check_chunk_size = 4*1024;
ACE_UINT8 buf[check_chunk_size];
while(!feof (pPatch))
{
size_t read = fread(buf, 1, check_chunk_size, pPatch);
MD5_Update(&ctx, buf, read);
}
fclose(pPatch);
// Store the result in the internal patch hash map
patches_[path] = new PATCH_INFO;
MD5_Final((ACE_UINT8 *) & patches_[path]->md5, &ctx);
}
bool PatchCache::GetHash(const char * pat, ACE_UINT8 mymd5[MD5_DIGEST_LENGTH])
{
for (Patches::iterator i = patches_.begin (); i != patches_.end (); i++)
if (!stricmp(pat, i->first.c_str ()))
{
memcpy(mymd5, i->second->md5, MD5_DIGEST_LENGTH);
return true;
}
return false;
}
void PatchCache::LoadPatchesInfo()
{
ACE_DIR* dirp = ACE_OS::opendir(ACE_TEXT("./patches/"));
if(!dirp)
return;
ACE_DIRENT* dp;
while((dp = ACE_OS::readdir(dirp)) != NULL)
{
int l = strlen(dp->d_name);
if (l < 8)
continue;
if(!memcmp(&dp->d_name[l - 4], ".mpq", 4))
LoadPatchMD5(dp->d_name);
}
ACE_OS::closedir(dirp);
}