Move git root from Client/ to src/ to track all source code: - Client: Game client source (moved to Client/Client/) - Server: Game server source - GameTools: Development tools - CryptoSource: Encryption utilities - database: Database scripts - Script: Game scripts - rylCoder_16.02.2008_src: Legacy coder tools - GMFont, Game: Additional resources 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
400 lines
11 KiB
C++
400 lines
11 KiB
C++
// ManageClient.cpp : Defines the entry point for the application.
|
|
//
|
|
#include "stdafx.h"
|
|
#include "resource.h"
|
|
#include "ManageClient.h"
|
|
|
|
#include <shellapi.h>
|
|
|
|
#include <Thread/Lock.h> // CNamedMutex
|
|
#include <Log/ServerLog.h>
|
|
#include <Utility/Debug/ExceptionReport.h> // g_CExceptionReport
|
|
#include <Utility/Time/Pulse/Pulse.h>
|
|
#include <Utility/Setup/ServerSetup.h>
|
|
|
|
#include <Network/Session/CreatePolicy.h>
|
|
#include <Network/Session/Session.h>
|
|
#include <Network/IOCP/IOCPNet.h>
|
|
|
|
#include <Network/Dispatch/ManageClient/ManageClientDispatch.h>
|
|
|
|
#include <Network/Packet/ManagePacketCmd.h>
|
|
#include <Network/Dispatch/SendManagePacket.h>
|
|
|
|
#include <Setup/SetupClient.h>
|
|
|
|
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
|
{
|
|
CNamedMutex Mutex("ManageClient", TRUE);
|
|
|
|
if(GetLastError() == ERROR_ALREADY_EXISTS)
|
|
{
|
|
ERRLOG0(g_Log, "ManageClient already server operating now. please shutdown and restart");
|
|
return 0;
|
|
}
|
|
|
|
unsigned long dwExceptionFeatures = CExceptionReport::CATCH_EXCEPTION |
|
|
CExceptionReport::USE_MINIDUMP | CExceptionReport::USE_REPORT;
|
|
|
|
CExceptionReport::GetInstance().Enable(dwExceptionFeatures);
|
|
|
|
CManageClient& ManageClient = CManageClient::GetInstance();
|
|
|
|
if(ManageClient.Initialize(hInstance,
|
|
CServerSetup::GetInstance().GetManageClientWindowName(),
|
|
lpCmdLine, IDI_MANAGECLIENT, IDC_MANAGECLIENT))
|
|
{
|
|
ManageClient.ProcessMessage();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
class CManageClientProcessThread : public CProcessThread
|
|
{
|
|
public:
|
|
|
|
enum Const
|
|
{
|
|
PROCESS_TPP = 200, // 200ms(0.2초) 에 1틱.
|
|
CONNECT_CHECK = 10 * (1000 / PROCESS_TPP), // 10초마다 연결 체크
|
|
PRINT_CHECK = 2 * (1000 / PROCESS_TPP), // 2초마다 콘솔 출력
|
|
PROCESS_CHECK = 3 * (1000 / PROCESS_TPP) // 5초마다 처리 갱신
|
|
};
|
|
|
|
CManageClientProcessThread(CManageClient& ManageClient)
|
|
: CProcessThread(ManageClient, PROCESS_TPP),
|
|
m_ManageClient(ManageClient)
|
|
{
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
virtual void Cleanup(CPulse& Pulse)
|
|
{
|
|
|
|
}
|
|
|
|
virtual void InternalRun(CPulse& Pulse)
|
|
{
|
|
unsigned long dwCurrentPulse = Pulse.GetCurrentPulse();
|
|
|
|
if(0 == (dwCurrentPulse % CONNECT_CHECK))
|
|
{
|
|
m_ManageClient.CheckConnectionAndReconnect();
|
|
}
|
|
|
|
if(0 == (dwCurrentPulse % PRINT_CHECK))
|
|
{
|
|
m_ManageClient.PrintConnectionStatus();
|
|
}
|
|
|
|
if(0 == (dwCurrentPulse % PROCESS_CHECK))
|
|
{
|
|
GET_SINGLE_DISPATCH(lpManageClientDispatch,
|
|
CManageClientDispatch, CManageClientDispatch::GetDispatchTable());
|
|
|
|
if(0 != lpManageClientDispatch)
|
|
{
|
|
lpManageClientDispatch->CheckProcessStatus();
|
|
}
|
|
}
|
|
}
|
|
|
|
CManageClient& m_ManageClient;
|
|
};
|
|
|
|
|
|
CManageClient& CManageClient::GetInstance()
|
|
{
|
|
static CManageClient manageClient;
|
|
return manageClient;
|
|
}
|
|
|
|
|
|
CManageClient::CManageClient()
|
|
: m_lpClientSessionPolicy(SessionPolicy::CreateTCPPolicy<CManageClientDispatch>())
|
|
{
|
|
|
|
}
|
|
|
|
|
|
CManageClient::~CManageClient()
|
|
{
|
|
if(0 != m_lpClientSessionPolicy)
|
|
{
|
|
m_lpClientSessionPolicy->Release();
|
|
m_lpClientSessionPolicy = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void CManageClient::CheckConnectionAndReconnect()
|
|
{
|
|
bool bReconnect = false;
|
|
|
|
GET_SINGLE_DISPATCH(lpManageClientDispatch,
|
|
CManageClientDispatch, CManageClientDispatch::GetDispatchTable());
|
|
|
|
if(0 == lpManageClientDispatch)
|
|
{
|
|
// 연결이 안 되어 있으면 연결을 테스트함.
|
|
|
|
CIOCPNet* lpIOCP = GetIOCPNet();
|
|
|
|
if(0 != lpIOCP)
|
|
{
|
|
ConnectToManageServer();
|
|
}
|
|
}
|
|
else if(lpManageClientDispatch->DoPatchNow())
|
|
{
|
|
// 패치를 전부 받고, 패치하기 직전이다. 패치 프로세스를 시작한다.
|
|
DoSelfPatchProcess(*lpManageClientDispatch);
|
|
}
|
|
}
|
|
|
|
|
|
void CManageClient::ConnectToManageServer()
|
|
{
|
|
CIOCPNet* lpIOCP = GetIOCPNet();
|
|
|
|
if(0 != lpIOCP && 0 != m_lpClientSessionPolicy)
|
|
{
|
|
INET_Addr& manageServerAddr = ManageSetup::ClientSetup::GetInstance().GetManageServerAddr();
|
|
|
|
if(!lpIOCP->Connect(m_lpClientSessionPolicy, manageServerAddr.get_addr_string(),
|
|
manageServerAddr.get_port_in()))
|
|
{
|
|
DETLOG3(g_Log, "this:0x%p/IP:%15s/Port/%02d/ManageServer connect failed.",
|
|
this, manageServerAddr.get_addr_string(), manageServerAddr.get_port_in());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CManageClient::DoSelfPatchProcess(CManageClientDispatch& ClientDispatch)
|
|
{
|
|
/*
|
|
// temporary .bat file
|
|
static const TCHAR szTempBatContent[] =
|
|
_T(":Repeat\r\n")
|
|
_T("del \"%s\"\r\n") // execute file name(full path)
|
|
_T("if exist \"%s\" goto Repeat\r\n") // execute file name(full path)
|
|
_T(":Repeat2\r\n")
|
|
_T("rename %s %s\r\n") // first - temp file name(full path), second - execute file name only
|
|
_T("if not exist \"%s\" goto Repeat\r\n") // execute file name(full path)
|
|
_T("cd %s\r\n") // execute file path(full path)
|
|
_T("%s\r\n"); // execute file name(full path)
|
|
|
|
static const TCHAR szTempBatName[] = "_manageclient_selfpatch.bat" ;
|
|
|
|
TCHAR szFullPathModuleName[MAX_PATH]; // absolute path of calling .exe file
|
|
TCHAR szModulePath[MAX_PATH]; // Module path
|
|
TCHAR szModuleFileName[MAX_PATH]; // fileName
|
|
TCHAR szModuleExtension[NAX_PATH]; // extension
|
|
TCHAR szTempBatPathName[MAX_PATH]; // absolute path of temporary .bat file
|
|
|
|
memset(szFullPathModuleName, 0, sizeof(TCHAR) * MAX_PATH);
|
|
memset(szModulePath, 0, sizeof(TCHAR) * MAX_PATH);
|
|
memset(szTempBatPathName, 0, sizeof(TCHAR) * MAX_PATH);
|
|
|
|
bool bFailedGetName = true;
|
|
|
|
unsigned long dwPathLength = GetTempPath(MAX_PATH, szTempBatPathName);
|
|
if(0 < dwPathLength)
|
|
{
|
|
if(0 < _sntprintf(szTempBatPathName + dwPathLength, MAX_PATH - dwPathLength - 1,
|
|
"%s", szTempBatName))
|
|
{
|
|
szTempBatPathName[MAX_PATH - 1] = 0;
|
|
bFailedGetName = false;
|
|
}
|
|
}
|
|
|
|
const TCHAR* szErrorMessage = 0;
|
|
|
|
if(bFailedGetName)
|
|
{
|
|
szErrorMessage = _T("this:0x%p/Failed get tempbat file.");
|
|
}
|
|
else
|
|
{
|
|
dwPathLength = GetModuleFileName(NULL, szFullPathModuleName, MAX_PATH - 1);
|
|
szFullPathModuleName[MAX_PATH - 1] = 0;
|
|
|
|
_tsplitpath(szFullPathModuleName, 0, 0, szModuleFileName, szModuleExtension);
|
|
|
|
_sntprintf(szModuleFileName, szModuleExtension
|
|
|
|
szModuleFileName = _tcsrchr(szFullPathModuleName, _T('\\'));
|
|
if(0 == szModuleFileName)
|
|
{
|
|
szModuleFileName = _tcsrchr(szFullPathModuleName, _T('/'));
|
|
}
|
|
|
|
if(0 == szModuleFileName || 0 == dwPathLength)
|
|
{
|
|
szErrorMessage = _T("this:0x%p/Failed get module name.");
|
|
}
|
|
else
|
|
{
|
|
memcpy(szModulePath, szFullPathModuleName,
|
|
szModuleFileName - szFullPathModuleName);
|
|
|
|
szModulePath[szModuleFileName - szFullPathModuleName] = _T('\0');
|
|
++szModuleFileName;
|
|
|
|
HANDLE hBatFile = CreateFile(szTempBatPathName, GENERIC_WRITE, 0, NULL,
|
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) ;
|
|
|
|
if (INVALID_HANDLE_VALUE == hBatFile)
|
|
{
|
|
szErrorMessage = _T("this:0x%p/Temp bat file create failed.");
|
|
}
|
|
else
|
|
{
|
|
DWORD dwLength = 0;
|
|
|
|
unsigned long dwTempBatContentLen = _tcslen(szTempBatContent);
|
|
unsigned long dwFullPathModuleNameLen = _tcslen(szFullPathModuleName);
|
|
unsigned long dwTempPathFileLen = _tcslen(ClientDispatch.GetTempPatchFileName());
|
|
unsigned long dwModuleFileNameLen = _tcslen(szModuleFileName);
|
|
unsigned long dwModulePathLen = _tcslen(szModulePath);
|
|
|
|
TCHAR* szBatBuffer = new TCHAR[dwTempBatContentLen +
|
|
dwFullPathModuleNameLen * 4 +
|
|
dwTempPathFileLen +
|
|
dwModuleFileNameLen +
|
|
dwModulePathLen +
|
|
MAX_PATH];
|
|
|
|
int nLength = _sntprintf(szBatBuffer, MAX_PATH * 10 - 1, szTempBatContent,
|
|
szFullPathModuleName, // 지울 파일 이름
|
|
szFullPathModuleName, // 파일 존재 여부 체크
|
|
ClientDispatch.GetTempPatchFileName(), // 임시 파일 이름
|
|
szModuleFileName, // 바뀔 이름
|
|
szFullPathModuleName, // 바뀐 이름
|
|
szModulePath, // 경로 이동
|
|
szFullPathModuleName); // 실행
|
|
|
|
if(0 < nLength)
|
|
{
|
|
if(!WriteFile(hBatFile, szBatBuffer, _tcslen(szBatBuffer), &dwLength, NULL))
|
|
{
|
|
szErrorMessage = _T("this:0x%p/Temp bat file write content failed.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
szErrorMessage = _T("this:0x%p/Temp bat file make content failed.");
|
|
}
|
|
|
|
CloseHandle(hBatFile);
|
|
|
|
delete [] szBatBuffer;
|
|
ShellExecute(NULL, _T("open"), szTempBatContent, NULL, NULL, SW_HIDE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(0 != szErrorMessage)
|
|
{
|
|
ERRLOG1(g_Log, szErrorMessage, this);
|
|
}
|
|
else
|
|
{
|
|
// 패치 성공. 종료.
|
|
DETLOG1(g_Log, "this:0x%p/Patch success. restart now.", this);
|
|
PostMessage(GetWnd(), WM_DESTROY, 0, 0);
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
bool CManageClient::ApplicationSpecificInit(const TCHAR* szCmdLine)
|
|
{
|
|
const TCHAR* szErrorMessage = 0;
|
|
|
|
if(!InitializeMsgProc())
|
|
{
|
|
szErrorMessage = _T("this:0x%p/InitializeMsgProc failed");
|
|
}
|
|
else if(!InitializeCommand())
|
|
{
|
|
szErrorMessage = _T("this:0x%p/InitializeCommand failed");
|
|
}
|
|
else if(!AddProcessThread(new CManageClientProcessThread(*this)))
|
|
{
|
|
szErrorMessage = "this:0x%p/AddProcessThread failed";
|
|
}
|
|
|
|
if(0 != szErrorMessage)
|
|
{
|
|
ERRLOG1(g_Log, szErrorMessage, this);
|
|
return false;
|
|
}
|
|
|
|
CheckConnectionAndReconnect();
|
|
return true;
|
|
}
|
|
|
|
|
|
void CManageClient::PrintConnectionStatus()
|
|
{
|
|
const int MAX_BUFFER = 4096;
|
|
char szBuffer[MAX_BUFFER];
|
|
|
|
char szFileName[MAX_PATH];
|
|
char szExtension[MAX_PATH];
|
|
|
|
INET_Addr& manageServerAddr = ManageSetup::ClientSetup::GetInstance().GetManageServerAddr();
|
|
|
|
GET_SINGLE_DISPATCH(lpManageClientDispatch,
|
|
CManageClientDispatch, CManageClientDispatch::GetDispatchTable());
|
|
|
|
int nLength = _snprintf(szBuffer, MAX_BUFFER - 1,
|
|
"ManageClient Console\r\n\r\nManageServer IP:%s, Port:%d %s\r\n\r\n",
|
|
manageServerAddr.get_addr_string(),
|
|
manageServerAddr.get_port_in(),
|
|
(0 != lpManageClientDispatch) ? "Connected" : "Disconnected");
|
|
|
|
int nTotalLength = 0;
|
|
|
|
if(0 < nLength)
|
|
{
|
|
if(0 != lpManageClientDispatch)
|
|
{
|
|
nTotalLength += nLength;
|
|
|
|
CManageClientDispatch::RunTable& runTable = lpManageClientDispatch->GetRunTable();
|
|
|
|
CManageClientDispatch::RunTable::iterator pos = runTable.begin();
|
|
CManageClientDispatch::RunTable::iterator end = runTable.end();
|
|
|
|
for(; pos != end; ++pos)
|
|
{
|
|
const ServerManage::RunInfo& runInfo = pos->second.m_RunInfo;
|
|
|
|
_splitpath(runInfo.m_szPath, 0, 0, szFileName, szExtension);
|
|
|
|
nLength = _snprintf(szBuffer + nTotalLength, MAX_BUFFER - nTotalLength,
|
|
"RunID:%5d / %s%s %s\r\n",
|
|
runInfo.m_dwRunID, szFileName, szExtension, runInfo.m_szOption);
|
|
|
|
if(0 < nLength)
|
|
{
|
|
nTotalLength += nLength;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(0 < nTotalLength && nTotalLength < MAX_BUFFER)
|
|
{
|
|
szBuffer[nTotalLength] = 0;
|
|
PrintInfo(szBuffer);
|
|
}
|
|
}
|
|
} |