#include "stdafx.h" #include "Entry.h" #include "Database.h" #include "CrashHandler.h" #include "TestCounter.h" #include "MonitorProcess.h" #include #ifdef _DEBUG eXtreme::Console g_console( SERVICE_VERSION ); #endif FILE* g_fpLog = NULL; void ErrorHandler( DWORD lastError, char* desc ) { OutputDebug( "Error = %d, %s\n", lastError, desc ); } void OutputDebug( char* format, ... ) { static WORD prevDay = 0; SYSTEMTIME systemTime; char buffer[4096] = {0, }; va_list args; //try{ va_start( args, format ); vsprintf( buffer, format, args ); va_end( args ); GetLocalTime( &systemTime ); if( prevDay != systemTime.wDay ) { SYSTEMTIME systemTime; char tmp[256] = {0, }; GetLocalTime( &systemTime ); #ifdef _DEBUG sprintf( tmp, "%s_%04d%02d%02d.txt", SERVICE_NAME, systemTime.wYear, systemTime.wMonth, systemTime.wDay); #else sprintf( tmp, "%s_%04d%02d%02d_%02d.txt", SERVICE_NAME, systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wHour ); #endif if( g_fpLog != 0 ) fclose( g_fpLog ); g_fpLog = fopen( tmp, "w+" ); prevDay = systemTime.wDay; } fprintf( g_fpLog, "[%02d/%02d %02d:%02d:%02d] %s", systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond, buffer ); fflush( g_fpLog ); #ifdef _DEBUG g_console.WriteLine( "[%02d/%02d %02d:%02d:%02d] %s", systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond, buffer ); #endif } void ParseCommand( char* cmdLine, int* argc, char args[10][32] ) { char delimit[] = " \t,\""; char* token = strtok( cmdLine, delimit ); while( token != 0 && *argc < 10 ) { // ÀÎÀÚ ÇϳªÀÇ ±æÀÌ´Â 32ÀÚ¸¦ ³ÑÁö ¸øÇÑ´Ù. strncpy( args[*argc], token, 32 ); ( *argc )++; token = strtok( 0, delimit ); } } int WINAPI WinMain( HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR lpCmdLine, int /*nCmdShow*/ ) { /////////////////////////////////////////////////////////////////////////////////////////////////// // For Windows service IfNotDebug() { char moduleName[1024] = {0, }; char args[10][32] = { {0, }, }; int argc = 0; // ÀÎÀÚ¸¦ ¾ò¾î¿Â´Ù. ParseCommand( lpCmdLine, &argc, args ); ::GetModuleFileName( 0, moduleName, 1024 ); strupr( args[0] ); if( argc > 0 ) { if( strncmp( args[0], "INSTALL", 7 ) == 0 ) { if( argc == 3 ) { eXtreme::WinService::Instance()->UploadService( SERVICE_NAME, SERVICE_NAME, moduleName, args[1], args[2], true ); } else if( argc == 1 ) { eXtreme::WinService::Instance()->UploadService( SERVICE_NAME, SERVICE_NAME, moduleName, 0, 0, true ); } return 0; } else if( strncmp( args[0], "REMOVE", 6 ) == 0 ) { eXtreme::WinService::Instance()->RemoveService( SERVICE_NAME ); return 0; } } } /////////////////////////////////////////////////////////////////////////////////////////////////// // Running Process if( eXtreme::Initialize( SERVICE_NAME, ErrorHandler ) == false ) { OutputDebug( "Already same server running.\n" ); return 0; } IfDebug() { // DebugÀÏ °æ¿ì Console Window·Î µ¿ÀÛÇÑ´Ù. Entry::Instance()->Initialize(); Entry::Instance()->WaitForTerminate(); Entry::Instance()->Destroy(); OutputDebug( "Press any key to abort program..." ); getch(); } else { // ReleaseÀÇ °æ¿ì Background Service·Î µ¿ÀÛÇØ¾ßÇÑ´Ù. // ÇÁ·Î±×·¥ÀÌ Á¾·áµÇ±â Àü ±îÁö StartDispatcher¿¡¼­ BlockµÈ´Ù. eXtreme::WinService::Instance()->StartDispatcher( SERVICE_NAME, Entry::OnServiceStart, Entry::OnServiceStop ); } return 0; } /////////////////////////////////////////////////////////////////////////////////////////////////////// bool Entry::OnServiceStart() { return Entry::Instance()->Initialize(); } void Entry::OnServiceStop() { Entry::Instance()->Destroy(); } Entry::Entry() : m_serviceRun( false ) { CrashHandler::Install( true, GenerateDmpName, ProcCrashHandling ); // Change director to execution file folder( just for Release ) IfNotDebug() { TCHAR fileName[1024] = {0, }; ::GetModuleFileName( 0, fileName, 1024 ); int len = ( int )::strlen( fileName ); int i = 0; for(i = len - 1 ; i >= 0 ; i-- ) { if( fileName[i] == '\\' ) break; } fileName[i] = 0; ::chdir( fileName ); } } Entry::~Entry() { if( g_fpLog != 0 ) fclose( g_fpLog ); } bool Entry::Initialize() { bool dbInitialized = false; { // RTTServer Á¤º¸ ::GetPrivateProfileString( "RTTServer", "IpAddress", "err", m_ipAddress, 20, SERVERINFO_FILENAME ); m_portNo = ::GetPrivateProfileInt( "RTTServer", "PortNo", 0, SERVERINFO_FILENAME ); // Wops Component Á¤º¸ ::GetPrivateProfileString( "Wops Component", "IpAddress", "err", m_ipAddressWops, 20, SERVERINFO_FILENAME ); m_portNoWops = ::GetPrivateProfileInt( "Wops Component", "PortNo", 0, SERVERINFO_FILENAME ); // RTTService Á¤º¸ ::GetPrivateProfileString( "RTTService", "IpAddress", "err", m_ipAddressService, 20, SERVERINFO_FILENAME ); m_portNoService = ::GetPrivateProfileInt( "RTTService", "PortNo", 0, SERVERINFO_FILENAME ); #ifdef _090427_HTTP_WEB_DROP_USER // Web Component Á¤º¸ ::GetPrivateProfileString( "Web Component", "IpAddress", "0.0.0.0", m_ipAddressWeb, 20, SERVERINFO_FILENAME ); m_portNoWeb = ::GetPrivateProfileInt( "Web Component", "PortNo", 6274, SERVERINFO_FILENAME ); #endif // RTTAgent Version Á¤º¸ m_dwRTTAgentVersion = ::GetPrivateProfileInt( "RTTAgent", "Version", 0, SERVERINFO_FILENAME ); } #ifdef TESTCOUNTER // TestCounter ÃʱâÈ­ { TestCounter::Counter* counter; counter = TestCounter::Instance()->Add( COUNTER_RTTA_SENDPACKET ); counter->Start(); counter = TestCounter::Instance()->Add( COUNTER_RTTA_SENDTRANSBYTES ); counter->Start(); counter = TestCounter::Instance()->Add( COUNTER_RTTA_RECVPACKET ); counter->Start(); counter = TestCounter::Instance()->Add( COUNTER_RTTA_RECVTRANSBYTES ); counter->Start(); counter = TestCounter::Instance()->Add( COUNTER_WOPS_SENDPACKET ); counter->Start(); counter = TestCounter::Instance()->Add( COUNTER_WOPS_SENDTRANSBYTES ); counter->Start(); counter = TestCounter::Instance()->Add( COUNTER_WOPS_RECVPACKET ); counter->Start(); counter = TestCounter::Instance()->Add( COUNTER_WOPS_RECVTRANSBYTES ); counter->Start(); } #endif OutputDebug( "%s\n\n", SERVICE_VERSION ); OutputDebug( "RTTAgent ver. v%d.00\n\n", m_dwRTTAgentVersion ); OutputDebug( "[Acceptor info for RTTClient] %s/%d\n", m_ipAddress, m_portNo ); OutputDebug( "[Acceptor info for WOPS Component] %s/%d\n", m_ipAddressWops, m_portNoWops ); OutputDebug( "[Acceptor info for RTTService] %s/%d\n", m_ipAddressService, m_portNoService ); #ifdef _090427_HTTP_WEB_DROP_USER OutputDebug( "[Acceptor info for Web Component] %s/%d\n", m_ipAddressWeb, m_portNoWeb ); #endif // Wops ComponentÃøÀÇ NetworkÀº ¹Ì¸® ¿ÀÇÂÇÑ´Ù. int nThreadCount = ::GetPrivateProfileInt( "RTTServer", "ThreadCount" , 6, SERVERINFO_FILENAME ); m_networkWops.Create(20, ManagerWops::Instance(), nThreadCount); // 500À̾ú»ï... 20À¸·Î ÁÙ¿©ÁÖ... (KJH : "¾îÂ¥ÇÇ ¿û½º´Â ¿ø¼¼¼ÇÀ̱⠶§¹®¿¡.." ) /* WOPS¿¡ WEB Service ¸¦ È£Ãâ ÇÒ Network HTTP´Â send/recv ¹Ýº¹ ÇüÅ·ΠÇÁ·ÎÅäÄÝÀÌ µÇ¾î ÀÖÀ¸³ª ¿©±â¼­´Â send¸¦ º¸³»°í error´Â ·Î±×·Î È®ÀÎÀ» ÇÑ´Ù. */ //m_networkWS.Create(1, ManagerWSSession::Instance()); if( m_networkWops.OpenAcceptor( m_ipAddressWops, ( u_short )m_portNoWops ) == false ) { OutputDebug( "[%s/%d] Binding failed.\n", m_ipAddressWops, m_portNoWops ); return false; } // Database·ÎºÎÅÍ ÇÊ¿äÁ¤º¸¸¦ ·ÎµåÇÑ´Ù. // Main threadÀÇ °¡µ¿ ÀÌÀü¿¡ ÀÛ¾÷µÇ¾î¾ß ÇÑ´Ù. dbInitialized = Database::Instance()->Create(); // Run thread °¡µ¿ { m_eventKill = ::CreateEvent( 0, 0, 0, 0 ); Start(); } return true; } void Entry::Destroy() { #ifdef TESTCOUNTER // TestCounter Á¾·á { TestCounter::Counter* counter[4]; counter[0] = TestCounter::Instance()->Get( COUNTER_RTTA_SENDPACKET ); counter[0]->Stop(); counter[1] = TestCounter::Instance()->Get( COUNTER_RTTA_SENDTRANSBYTES ); counter[1]->Stop(); counter[2] = TestCounter::Instance()->Get( COUNTER_RTTA_RECVPACKET ); counter[2]->Stop(); counter[3] = TestCounter::Instance()->Get( COUNTER_RTTA_RECVTRANSBYTES ); counter[3]->Stop(); OutputDebug( "** TestCounter Report **\n" ); OutputDebug( "[RTTAgent]\n" ); OutputDebug( "Test time : %d ms\n", counter[0]->GetTimeGap() ); OutputDebug( "Sent packet count = %d(%d)\n", counter[0]->GetCount(), counter[0]->GetCount() / 1000 ); OutputDebug( "Sent transbytes = %d(%d)\n", counter[1]->GetCount(), counter[1]->GetCount() / 1000 ); OutputDebug( "Recv packet count = %d(%d)\n", counter[2]->GetCount(), counter[2]->GetCount() / 1000 ); OutputDebug( "Recv transbytes = %d(%d)\n", counter[3]->GetCount(), counter[3]->GetCount() / 1000 ); counter[0] = TestCounter::Instance()->Get( COUNTER_WOPS_SENDPACKET ); counter[0]->Stop(); counter[1] = TestCounter::Instance()->Get( COUNTER_WOPS_SENDTRANSBYTES ); counter[1]->Stop(); counter[2] = TestCounter::Instance()->Get( COUNTER_WOPS_RECVPACKET ); counter[2]->Stop(); counter[3] = TestCounter::Instance()->Get( COUNTER_WOPS_RECVTRANSBYTES ); counter[3]->Stop(); OutputDebug( "[WOPS Component]\n" ); OutputDebug( "Test time : %d ms\n", counter[0]->GetTimeGap() ); OutputDebug( "Sent packet count = %d(%d)\n", counter[0]->GetCount(), counter[0]->GetCount() / 1000 ); OutputDebug( "Sent transbytes = %d(%d)\n", counter[1]->GetCount(), counter[1]->GetCount() / 1000 ); OutputDebug( "Recv packet count = %d(%d)\n", counter[2]->GetCount(), counter[2]->GetCount() / 1000 ); OutputDebug( "Recv transbytes = %d(%d)\n", counter[3]->GetCount(), counter[3]->GetCount() / 1000 ); TestCounter::Instance()->RemoveAll(); } #endif // Run thread¸¦ Á¾·á½ÃŲ´Ù. { ::SetEvent( m_eventKill ); if( WaitForTerminate( 1000 ) == false ) Terminate( 0 ); ::CloseHandle( m_eventKill ); m_eventKill = INVALID_HANDLE_VALUE; } m_networkWops.CloseAcceptor(); m_networkWops.Destroy(); //m_networkWS.Destroy(); ServiceTerminate(); Database::Instance()->Destroy(); } void Entry::ServiceStartUp() { int maxRTTACount = ::GetPrivateProfileInt( "RTTServer", "MaxRTTACount", 100, SERVERINFO_FILENAME ); int nThreadCount = ::GetPrivateProfileInt( "RTTServer", "ThreadCount" , 6, SERVERINFO_FILENAME ); // RTTAgentÃøÀÇ NetworkÀº ServiceStartUp¿¡¼­ ¿ÀÇÂÇÑ´Ù. m_networkClient.Create ( (WORD)maxRTTACount, ManagerClient::Instance() , nThreadCount ); m_networkService.Create( (WORD)maxRTTACount, ManagerService::Instance(), nThreadCount ); #ifdef _090427_HTTP_WEB_DROP_USER m_networkWeb.Create ( 50, ManagerWeb::Instance() , nThreadCount ); #endif if( m_networkClient.OpenAcceptor( m_ipAddress, ( u_short )m_portNo ) == false ) { OutputDebug( "[%s/%d] Binding failed.\n", m_ipAddress, m_portNo ); return; } if( m_networkService.OpenAcceptor( m_ipAddressService, ( u_short )m_portNoService ) == false ) { OutputDebug( "[%s/%d] Binding failed.\n", m_ipAddressService, m_portNoService ); return; } #ifdef _090427_HTTP_WEB_DROP_USER if( m_networkWeb.OpenAcceptor( m_ipAddressWeb, ( u_short )m_portNoWeb ) == false ) { OutputDebug( "[%s/%d] Binding failed.\n", m_ipAddressWeb, m_portNoWeb ); return; } #endif m_serviceRun = true; OutputDebug( "!-*-*-* Service Started *-*-*-!\n\n" ); } void Entry::ServiceTerminate() { if(m_serviceRun) { m_networkClient.CloseAcceptor(); m_networkService.CloseAcceptor(); /* RTTAgent / RTTService ¿¬°á ¼ÒÄÏ Á¤¸® */ ManagerClient::Instance()->DisconnectAll(); ManagerService::Instance()->DisconnectAll(); m_networkClient.Destroy(); m_networkService.Destroy(); #ifdef _090427_HTTP_WEB_DROP_USER m_networkWeb.CloseAcceptor(); ManagerWeb::Instance()->DisconnectAll(); m_networkWeb.Destroy(); #endif MonitorProcess::Instance()->Clear(); m_serviceRun = false; OutputDebug( "!-*-*-* Service Closed *-*-*-!\n\n" ); } } void Entry::Run() { while( true ) { if( ::WaitForSingleObject( m_eventKill, 10 ) == WAIT_OBJECT_0 ) break; if( m_serviceRun == true ) { m_networkClient.Update(); m_networkService.Update(); //m_networkWS.Update(); } m_networkWops.Update(); IfDebug() { if( kbhit() != 0 ) { if( getch() == 27 ) break; } } } } void Entry::ProcCrashHandling( LPCTSTR stackWalkLog, LPCTSTR dumpFileName ) { FILE* fp = NULL; SYSTEMTIME systemTime; TCHAR temp[127] = {0, }; GetLocalTime( &systemTime ); sprintf( temp, "RTTServer CrashLog_%d%02d%02d_%02d%02d%02d.txt", systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond ); fp = fopen( temp, "w" ); fprintf( fp, "Dump file path : %s\r\n\r\n", dumpFileName ); fprintf( fp, stackWalkLog ); fclose( fp ); // Report to console screen IfDebug() { OutputDebug( "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" ); OutputDebug( "This application occured an unknown error as follow...\n\n" ); OutputDebug( "%s\n", stackWalkLog ); OutputDebug( "This report and memory dump which is %s file\n sent to reinlainer@webzen.co.kr.\n", dumpFileName ); OutputDebug( "\n\nPress any key to abort application...." ); getch(); } } LPCTSTR Entry::GenerateDmpName() { static char fileName[64] = {0, }; SYSTEMTIME time; ::GetLocalTime( &time ); ::sprintf( fileName, "%s_%d%d%d_%d%d.dmp", SERVICE_NAME, time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute ); return fileName; }