Files
Sun1602/Tools/SunUpdateManager/SunUpdateAgent/SunUpdateAgent.cpp
T
2022-10-26 12:25:11 +08:00

650 lines
18 KiB
C++

#include "stdafx.h"
#include "SunUpdateAgent.h"
#include <IOCPServer.h>
#include <PublicDefine.h>
#include "AgentInfoParser.h"
#include <conio.h>
#include <io.h>
#include <SolarDump.h>
#include "UpdateToolSessionFactory.h"
#include "UpdateServerSession.h"
#include "PacketHandler.h"
#include "AgentInfoParser.h"
#include <process.h>
#include "PacketStruct_SA.h"
#include <FileUtil.h>
#ifdef _NA_006662_20130423_SVNPATCH
#include <PacketStruct_AT.h>
#define MAX_LINELENGTH 30+1
#endif //_NA_006662_20130423_SVNPATCH
/************************************************************************/
/* 콜백함수 */
/************************************************************************/
NetworkObject* CreateClientSideAcceptedObject();
VOID DestroyClientSideAcceptedObject( NetworkObject * pNetworkObject );
VOID DestroyClientSideConnectedObject( NetworkObject * pNetworkObject );
NetworkObject* CreateServerSideAcceptedObject();
VOID DestroyServerSideAcceptedObject( NetworkObject * pNetworkObject );
VOID DestroyServerSideConnectedObject( NetworkObject * pNetworkObject );
SunUpdateAgent::SunUpdateAgent()
{
m_pIOCPServer = NULL;
m_bIsShutDown = FALSE;
m_wInnerPort = 0;
m_wOutSidePort = 0;
m_dwAgentKey = 0;
m_pUpdateServerSession = NULL;
m_dwFPS = 0;
m_bRunCheckThread = FALSE;
#ifdef _NA_006662_20130423_SVNPATCH
patching_svnmode_ = FALSE;
patching_userkey_=0;
#endif //_NA_006662_20130423_SVNPATCH
}
SunUpdateAgent::~SunUpdateAgent()
{
}
VOID SunUpdateAgent::Release()
{
if( m_pIOCPServer )
{
m_pIOCPServer->Shutdown();
SAFE_DELETE( m_pIOCPServer );
}
UpdateToolSessionFactory::Instance()->DestroyInstance();
SAFE_DELETE( m_pUpdateServerSession );
PacketHandler::Instance()->DestroyInstance();
AgentInfoParser::DestroyInstance();
}
BOOL SunUpdateAgent::Init()
{
//////////////////////////////////////////////////////////////////////////
// 서버 스크립트 읽고 구조체에 적용.
if( !AgentInfoParser::Instance()->Load("./UpdateAgent.ini") )
{
MSGOUT( "UpdateAgent.ini 로드 실패" );
return FALSE;
}
SERVER_ENV* pServerEnv = AgentInfoParser::Instance()->GetServerEnv();
if( !pServerEnv )
{
MSGOUT( "pServerEnv 가져오기 실패" );
return FALSE;
}
#ifdef __20101123__UPDATE_AGENT_AUTO_RESTART
AgentInfoParser::Instance()->ScheduleNextStop(m_AutoStopSchedule);
AgentInfoParser::Instance()->ScheduleNextStart(m_AutoStartSchedule);
#endif
//////////////////////////////////////////////////////////////////////////
// Factory Creator
UpdateToolSessionFactory::Instance()->Init( pServerEnv->ClientIoHandler.dwMaxAcceptSession );
IOHANDLER_DESC desc[2];
desc[0].dwIoHandlerKey = CLIENT_IOHANDLER;
desc[0].dwMaxAcceptSession = pServerEnv->ClientIoHandler.dwMaxAcceptSession;
desc[0].dwMaxConnectSession = pServerEnv->ClientIoHandler.dwMaxConnectSession;
desc[0].dwSendBufferSize = pServerEnv->ClientIoHandler.dwSendBufferSize;
desc[0].dwRecvBufferSize = pServerEnv->ClientIoHandler.dwRecvBufferSize;
desc[0].dwTimeOut = pServerEnv->ClientIoHandler.dwTimeOut;
desc[0].dwNumberOfAcceptThreads = pServerEnv->ClientIoHandler.dwNumberOfAcceptThreads;
desc[0].dwNumberOfIoThreads = pServerEnv->ClientIoHandler.dwNumberOfIoThreads;
desc[0].dwNumberOfConnectThreads = pServerEnv->ClientIoHandler.dwNumberOfConnectThreads;
desc[0].dwMaxPacketSize = pServerEnv->ClientIoHandler.dwMaxPacketSize;
desc[0].fnCreateAcceptedObject = CreateClientSideAcceptedObject;
desc[0].fnDestroyAcceptedObject = DestroyClientSideAcceptedObject;
desc[0].fnDestroyConnectedObject = DestroyClientSideConnectedObject;
m_strOutSideIP = pServerEnv->ClientIoHandler.szIP;
m_wOutSidePort = pServerEnv->ClientIoHandler.wPort;
desc[1].dwIoHandlerKey = SERVER_IOHANDLER;
desc[1].dwMaxAcceptSession = pServerEnv->ServerIoHandler.dwMaxAcceptSession;
desc[1].dwMaxConnectSession = pServerEnv->ServerIoHandler.dwMaxConnectSession;
desc[1].dwSendBufferSize = pServerEnv->ServerIoHandler.dwSendBufferSize;
desc[1].dwRecvBufferSize = pServerEnv->ServerIoHandler.dwRecvBufferSize;
desc[1].dwTimeOut = pServerEnv->ServerIoHandler.dwTimeOut;
desc[1].dwNumberOfAcceptThreads = pServerEnv->ServerIoHandler.dwNumberOfAcceptThreads;
desc[1].dwNumberOfIoThreads = pServerEnv->ServerIoHandler.dwNumberOfIoThreads;
desc[1].dwNumberOfConnectThreads = pServerEnv->ServerIoHandler.dwNumberOfConnectThreads;
desc[1].dwMaxPacketSize = pServerEnv->ServerIoHandler.dwMaxPacketSize;
desc[1].fnCreateAcceptedObject = CreateServerSideAcceptedObject;
desc[1].fnDestroyAcceptedObject = DestroyServerSideAcceptedObject;
desc[1].fnDestroyConnectedObject = DestroyServerSideConnectedObject;
m_strInSideIP = pServerEnv->ServerIoHandler.szIP;
m_wInnerPort = pServerEnv->ServerIoHandler.wPort;
m_pIOCPServer = new IOCPServer;
if( !m_pIOCPServer->Init( desc, 2 ) )
return FALSE;
DISPMSG( ">> client-side max connection: accept(%d), connect(%d) \n", desc[0].dwMaxAcceptSession, desc[0].dwMaxConnectSession );
DISPMSG( ">> server-side max connection: accept(%d), connect(%d) \n", desc[1].dwMaxAcceptSession, desc[1].dwMaxConnectSession );
/************************************************************************/
/* Connector */
/************************************************************************/
m_pUpdateServerSession = new UpdateServerSession;
AddressInfo rUpdateServer = AgentInfoParser::Instance()->GetUpdateServerInfo();
SetUpdateServerIPAddr( rUpdateServer.m_szServerIP, rUpdateServer.m_wServerPort );
ConnectToUpdateServer();
//UserListen Start
StartClientSideListen();
return TRUE;
}
BOOL SunUpdateAgent::Update()
{
if( IsShutDown() )
return FALSE;
m_pIOCPServer->Update();
#ifdef __20101123__UPDATE_AGENT_AUTO_RESTART
if (m_AutoStopSchedule.IsValid() || m_AutoStartSchedule.IsValid()) {
UpdateForAutoRestart();
}
#endif
#ifdef _NA_006662_20130423_SVNPATCH
DWORD patch_style = AgentInfoParser::Instance()->GetPatchStyle();
if (patch_style == AgentInfoParser::ePATCH_STYLE::PATCHSTYLE_SVN &&
GetPatchingSVNmode() == TRUE)
{
CheckPatchProcess();
}
#endif //_NA_006662_20130423_SVNPATCH
UpdateFPS();
return TRUE;
}
VOID SunUpdateAgent::Run()
{
while( TRUE )
{
Sleep( 1 );
if( !Update() ) break;
if( !ProcessConsole() ) return;
}
}
VOID SunUpdateAgent::DisplayAgentInfo()
{
DISPMSG( "============== SunUpdateAgent ==============\n" );
DISPMSG( "Frame Per Second : %d\n", m_dwFPS );
DISPMSG( "UpdateTool Connection : %d\n", m_pIOCPServer->GetNumberOfConnections( CLIENT_IOHANDLER ) );
DISPMSG( "UpdateServer Connection : %d\n", m_pUpdateServerSession->IsConnected() );
}
VOID SunUpdateAgent::UpdateFPS()
{
// FPS Check
static int cnt = 0;
static DWORD prevTick = GetTickCount();
cnt++;
DWORD curTick = GetTickCount();
if( prevTick + 1000 < curTick )
{
m_dwFPS = cnt;
prevTick = curTick;
cnt = 0;
if( m_dwFPS < 10 )
{
DISPMSG( "============================================================\n" );
DISPMSG( "[SunUpdateAgent::UpdateFPS] FPS Warning!!! [%d] \n", m_dwFPS );
DISPMSG( "============================================================\n" );
}
}
}
#ifdef __20101123__UPDATE_AGENT_AUTO_RESTART
void SunUpdateAgent::UpdateForAutoRestart()
{
static DWORD last_tick = ::GetTickCount();
DWORD current_tick = ::GetTickCount();
if (Schedule::GetDifference(last_tick, current_tick) >= 1000)
{
int remaining_seconds;
last_tick = current_tick;
if (m_AutoStopSchedule.IsValid()) {
remaining_seconds = m_AutoStopSchedule.SecondsTo();
if (remaining_seconds <= 0) {
ScheduleToken token;
AgentInfoParser::Instance()->ScheduleNextStop(token);
if (!m_AutoStopSchedule.IsEquivalent(token))
{
MSGOUT("Auto-stop time: %s", m_AutoStopSchedule.ToString());
AutoStop();
m_AutoStopSchedule = token;
MSGOUT("Next auto-stop time: %s", m_AutoStopSchedule.ToString());
return;
}
}
}
if (m_AutoStartSchedule.IsValid()) {
remaining_seconds = m_AutoStartSchedule.SecondsTo();
if (remaining_seconds <= 0) {
ScheduleToken token;
AgentInfoParser::Instance()->ScheduleNextStart(token);
if (!m_AutoStartSchedule.IsEquivalent(token))
{
MSGOUT("Auto-start time: %s", m_AutoStartSchedule.ToString());
AutoStart();
m_AutoStartSchedule = token;
MSGOUT("Next auto-start time: %s", m_AutoStartSchedule.ToString());
return;
}
}
}
}
}
void SunUpdateAgent::AutoStop()
{
static const int NUM_SERVER_TYPES = 7;
static BYTE server_types[NUM_SERVER_TYPES] = {
5, // WorldServer
1, // AgentServer
//11, // PortalServer
//7, // GuildServer
3, // BattleServer
2, // FieldServer
4, // DatabaseProxy
};
MSGOUT("Auto-stopping...");
for (int i = 0; i < NUM_SERVER_TYPES; ++i) {
StopServer(server_types[i]);
}
}
void SunUpdateAgent::AutoStart()
{
static const int NUM_SERVER_TYPES = 7;
static BYTE server_types[NUM_SERVER_TYPES] = {
4, // DatabaseProxy
//7, // GuildServer
//11, // PortalServer
5, // WorldServer
2, // FieldServer
3, // BattleServer
1, // AgentServer
};
MSGOUT("Auto-starting...");
for (int i = 0; i < NUM_SERVER_TYPES; ++i) {
StartServer(server_types[i]);
}
}
void SunUpdateAgent::StopServer(BYTE server_type)
{
std::string process_name;
AgentInfoParser::Instance()->GetGameProcessName(server_type, process_name);
DWORD process_id = 0;
CheckLiveProcess((TCHAR*)process_name.c_str(), process_id, 0);
if (process_id != 0)
{
if(ServerForceShutDown(process_id))
{
MSGOUT("강제서버종료 성공: Name = %s", process_name.c_str());
}
else
{
MSGOUT("강제서버종료 실패: Name = %s", process_name.c_str());
}
}
}
void SunUpdateAgent::StartServer(BYTE server_type)
{
std::string process_name, path;
AgentInfoParser::Instance()->GetGameProcessName(server_type, process_name);
AgentInfoParser::Instance()->GetGameServerPath(server_type, path);
DWORD process_id = 0;
CheckLiveProcess((TCHAR*)process_name.c_str(), process_id, 0);
if (process_id != 0) {
MSGOUT("이미 실행 중: %s", path.c_str());
return;
}
std::string directory_path = path.substr(0, path.rfind('\\'));
if(_access(path.c_str(), 0) != -1)
{
#ifdef __20080312__SOLARAUTH_SERVER_PATCH
PROCESS_INFORMATION pi;
STARTUPINFO si = {0, };
si.cb = sizeof(si);
if( CreateProcess( path.c_str(), NULL,
NULL, NULL, TRUE,
CREATE_NEW_CONSOLE,
NULL, directory_path.c_str(),
&si, &pi) )
{
MSGOUT("서버실행 성공: %s", path.c_str());
}
#else
if(WinExec(path.c_str(), SW_SHOW ) > 31)
{
MSGOUT("서버실행 성공: %s", path.c_str());
}
#endif //__20080312__SOLARAUTH_SERVER_PATCH
else
{
MSGOUT("서버실행 실패: %s", path.c_str());
}
}
else
{
MSGOUT("서버실행 실패(파일이 없습니다): %s" , path.c_str());
}
}
#endif // __20101123__UPDATE_AGENT_AUTO_RESTART
BOOL SunUpdateAgent::ProcessConsole()
{
if( kbhit() )
{
char ch = getch();
ch = toupper(ch);
switch( ch )
{
case 0x1b:
MSGOUT( "Close UpdateAgent..." );
return FALSE;
case ' ':
DisplayAgentInfo();
break;
default:
break;
}
}
return TRUE;
}
#ifdef _NA_006662_20130423_SVNPATCH
void SunUpdateAgent::CheckPatchProcess()
{
DWORD process_id=0;
if (!CheckLiveProcess("py.exe", process_id))
{
SendPatchResultToServer_SVN();
SetPatchingSVNmode(FALSE);
SetPatchingUserKey(0);
}
}
VOID SunUpdateAgent::SendPatchResultToServer_SVN()
{
FILE* file = fopen("updatelog.txt", "r");
if(file == NULL)
return;
char buf[MAX_LINELENGTH];
fseek(file, -MAX_LINELENGTH, SEEK_END);
fread(buf, MAX_LINELENGTH-1, 1, file);
buf[MAX_LINELENGTH-1] = '\0';
char* last_new=NULL;
char* last_line=NULL;
last_new = strchr(buf, '\n');
if (last_new == NULL)
last_line = buf+1;
else
last_line = last_new+1;
char* str_temp = strtok(last_line, " ");
char* str_revision = strtok(NULL, "");
int revision = atoi(str_revision);
fclose(file);
MSG_SA_PATCH_RESULT_NTF msg;
msg.m_dwUserKey = GetPatchingUserKey();
msg.m_byNum = 0;
msg.m_byServerType = SUN_SERVER;
msg.m_PatchVer.m_byVer1 = 0;
msg.m_PatchVer.m_byVer2 = 0;
msg.m_PatchVer.m_byVer3 = 0;
if(strcmp(str_temp, "Update_Completed") == 0)
{
msg.m_dwResult = MSG_MO_RTTG_PATCHRESULT_ANS::ERROR_PATCHSUCCESS;
}
else if(strcmp(str_temp, "Update_Conflicted") == 0)
{
msg.m_dwResult = MSG_MO_RTTG_PATCHRESULT_ANS::ERROR_DOWNLOAD_FAIL;
}
else
{
msg.m_dwResult = MSG_MO_RTTG_PATCHRESULT_ANS::ERROR_FILENOTFOUND;
}
SendToUpdateServer(&msg, sizeof(msg));
}
#endif //_NA_006662_20130423_SVNPATCH
VOID SunUpdateAgent::StartClientSideListen()
{
if( !m_pIOCPServer->IsListening( CLIENT_IOHANDLER ) )
{
MSGOUT( "[SunUpdateAgent::StartClientSideListen] Starting ClientSidelisten(%s@%d)...", m_strOutSideIP.c_str(), m_wOutSidePort );
if( !m_pIOCPServer->StartListen( CLIENT_IOHANDLER, const_cast<char *>(m_strOutSideIP.c_str()), m_wOutSidePort ) )
{
MSGOUT( "[SunUpdateAgent::StartClientSideListen] Fail");
return ;
}
MSGOUT( "[SunUpdateAgent::StartClientSideListen] Success");
}
}
VOID SunUpdateAgent::SetUpdateServerIPAddr( const TCHAR* pszIP, WORD wPort )
{
m_pUpdateServerSession->SetAddr( pszIP, wPort );
}
BOOL SunUpdateAgent::SendToUpdateServer( VOID * pMsg, WORD wSize )
{
return m_pUpdateServerSession->Send( (BYTE*)pMsg, wSize );
}
DWORD SunUpdateAgent::ConnectToServer( NetworkObject* pNetworkObjet, const TCHAR* pszIP, WORD wPort )
{
if( !pNetworkObjet ) return FALSE;
//세션 Index를 리턴한다.
return m_pIOCPServer->Connect( SERVER_IOHANDLER, pNetworkObjet, const_cast<char*>(pszIP), wPort );
}
BOOL SunUpdateAgent::ConnectToUpdateServer()
{
if( !m_pUpdateServerSession ) return FALSE;
return m_pUpdateServerSession->TryToConnect();
}
VOID SunUpdateAgent::DisconnectUpdateServer()
{
if( !m_pUpdateServerSession ) return;
return m_pUpdateServerSession->Disconnect();
}
BOOL SunUpdateAgent::IsConnectUpdateServer()
{
if( !m_pUpdateServerSession ) return FALSE;
return m_pUpdateServerSession->IsConnected();
}
BOOL SunUpdateAgent::StartCheckGameServer()
{
//Update Thread 가동
unsigned int unThreadID = 1;
SunUpdateAgent::Instance()->m_bRunCheckThread = TRUE;
m_hCheckThread = (HANDLE)_beginthreadex (NULL, NULL, CheckGameServer, (void*)this, 0, &unThreadID);
if( m_hCheckThread == INVALID_HANDLE_VALUE )
{
SunUpdateAgent::Instance()->m_bRunCheckThread = FALSE;
MessageBox( NULL, "업데이트 쓰레드 생성 실패", NULL, MB_OK );
return FALSE;
}
return TRUE; // 만일 FALSE라면 업데이트 프로세스 종료
}
unsigned __stdcall CheckGameServer( VOID* pParam )
{
std::string strProcess;
BOOL bRet = FALSE;
DWORD dwPreGameServerProcID = 0;
while( SunUpdateAgent::Instance()->m_bRunCheckThread )
{
Sleep( AgentInfoParser::Instance()->GetIntervalTime() );
dwPreGameServerProcID = 0;
//ini 파일에 등록된 파일들의 쓰레드들을 체크한다.
GAMEPROCESS_MAP& rGameProcess = AgentInfoParser::Instance()->GetGameProcess();
for( GAMEPROCESS_MAP_ITER iter = rGameProcess.begin(); iter != rGameProcess.end(); ++iter )
{
std::string strProcess;
strProcess.clear();
strProcess = iter->second;
DWORD dwProID = 0;
bRet = CheckLiveProcess( (TCHAR*)strProcess.c_str(), dwProID, dwPreGameServerProcID );
MSG_SA_CHECK_GAMEPROCESS_NTF msg;
msg.m_GameStatus.m_ServerType = (eGAME_SERVER_TYPE)iter->first;
if( dwProID ) //존재하면.. 현재 실제 실행되고 있는 프로세서이다.
msg.m_GameStatus.m_Status = SERVER_STATUS_LIVE_PROCESS;
else //현재 프로세서가 존재하지 않으면...
msg.m_GameStatus.m_Status = SERVER_STATUS_OFFLINE;
SunUpdateAgent::Instance()->SendToUpdateServer( &msg, sizeof(msg) );
}
// assert 창 종료시키기.. "dwwin.exe" ==> 프로세스 명
DWORD dwWinProID = 0;
bRet = CheckLiveProcess( "dwwin.exe", dwWinProID, 0 );
if( bRet )
ServerForceShutDown( dwWinProID );
}
return 1;
}
//------------------------------------------------------------------------------------------------
// 클라이언트 콜백
//------------------------------------------------------------------------------------------------
NetworkObject * CreateClientSideAcceptedObject()
{
return (NetworkObject *)UpdateToolSessionFactory::Instance()->AllocToolSession( );
}
VOID DestroyClientSideAcceptedObject( NetworkObject * pNetworkObject )
{
UpdateToolSessionFactory::Instance()->FreeToolSession( (UpdateToolSession *)pNetworkObject );
}
VOID DestroyClientSideConnectedObject( NetworkObject * pNetworkObject )
{
}
//------------------------------------------------------------------------------------------------
// 서버 콜백
//------------------------------------------------------------------------------------------------
NetworkObject* CreateServerSideAcceptedObject()
{
//호출되면.. 이상한거다..
return NULL;
}
VOID DestroyServerSideAcceptedObject( NetworkObject * pNetworkObject )
{
//호출되면.. 이상한거다..
}
VOID DestroyServerSideConnectedObject( NetworkObject * pNetworkObject )
{
}
//------------------------------------------------------------------------------------------------
// Enum 콜백
//------------------------------------------------------------------------------------------------
BOOL CALLBACK EnumProc(HWND hWnd, LPARAM lParam)
{
DWORD dwPID = 0;
CallbackInfo *pst_Callback = (CallbackInfo *)lParam;
GetWindowThreadProcessId(hWnd, &dwPID);
if (pst_Callback->m_dwPID != dwPID)
return TRUE;
pst_Callback->m_hWnd = hWnd;
return FALSE;
}