#include "stdafx.h" #include "SunUpdateAgent.h" #include #include #include "AgentInfoParser.h" #include #include #include #include "UpdateToolSessionFactory.h" #include "UpdateServerSession.h" #include "PacketHandler.h" #include "AgentInfoParser.h" #include #include "PacketStruct_SA.h" #include #ifdef _NA_006662_20130423_SVNPATCH #include #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(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(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; }