Files
Client/Server/ManageTool/ManageClient/ManageClient.cpp
LGram16 dd97ddec92 Restructure repository to include all source folders
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>
2025-11-29 20:17:20 +09:00

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);
}
}
}