// Include #include "loginsrv.h" #include #include #pragma comment(lib, "dbghelp.lib") // Local definitions #define SafeDelete(P) if (P!=NULL) { delete(P); (P)=NULL; } // memory °²È«ÊÍ·Å #define SafeCloseHandle(P) if (P!=NULL) { CloseHandle(P); (P)=NULL; } // handle °²È«¹Ø±Õ #define ODBC_DSN_WEB "WEB_MEMBERDB" #define ODBC_DSN_ACCOUNT "IRIS_MEMBERDB" #define ODBC_UID_WEB "iris" // local test #define ODBC_PWD_WEB "vedsa239HPJam8Y" // local test #define ODBC_UID "iris" // IDC test #define ODBC_PWD "vedsa239HPJam8Y" // IDC test // Global data cLoginSrv* g_loginSrv = NULL; bool g_verbose = false; bool g_fps = false; bool g_packet = false; bool g_udp = false; bool g_udpPacket = false; bool g_udpFrom = false; u_short g_loginPort = 15002; u_short g_gamePort = 15004; u_short g_logPort = 15000; // ÉèÖ÷þÎñÃû³ÆºÍÏÔʾÃû³Æ - ĬÈÏ. TCHAR g_serviceName[MAX_PATH] = TEXT( "LoginServer" ); TCHAR g_description[MAX_PATH] = TEXT( "Copyright(c) 2009 EYA INTERACTIVE Corporation All rights reserved" ); TCHAR g_displayFmt[] = TEXT( "IRIS ON LINE - %s" ); // GetLogicalAddress Prototype BOOL __stdcall GetLogicalAddress(PVOID addr, PTSTR szModule, DWORD len, DWORD §ion, DWORD &offset) { #pragma warning( disable: 4311 ) #pragma warning( disable: 4312 ) MEMORY_BASIC_INFORMATION mbi; if ( !VirtualQuery( addr, &mbi, sizeof(mbi) ) ) return FALSE; DWORD hMod = (DWORD)mbi.AllocationBase; if ( !GetModuleFileName( (HMODULE)hMod, szModule, len ) ) return FALSE; PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod; PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(hMod + pDosHdr->e_lfanew); PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHdr); DWORD rva = (DWORD)addr - hMod; // RVA is offset from module load address for ( unsigned i = 0; i < pNtHdr->FileHeader.NumberOfSections; i++, pSection++ ) { DWORD sectionStart = pSection->VirtualAddress; DWORD sectionEnd = sectionStart + max( pSection->SizeOfRawData, pSection->Misc.VirtualSize ); if ( (rva >= sectionStart) && (rva <= sectionEnd) ) { section = i + 1; offset = rva - sectionStart; return TRUE; } } return FALSE; } // WriteStackDetails Prototype void WriteStackDetails(PCONTEXT context) { char fileName[MAX_PATH]; SYSTEMTIME st; char buffer[MAX_PATH]; GetLocalTime( &st ); sprintf_s( fileName ,MAX_PATH ,"LoginServer_%4d%02d%02d_%02d%02d.StackWalk" ,st.wYear ,st.wMonth ,st.wDay ,st.wHour ,st.wMinute ); FILE* stream = fopen( fileName, "wt" ); if ( stream != NULL ) { fputs( "#Fields: Address Frame Function SourceFile\n", stream ); STACKFRAME sf; memset( &sf, 0, sizeof(sf) ); // Initialize the STACKFRAME structure for the first call. This is only // necessary for Intel CPUs, and isn't mentioned in the documentation. sf.AddrPC.Offset = context->Eip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrStack.Offset = context->Esp; sf.AddrStack.Mode = AddrModeFlat; sf.AddrFrame.Offset = context->Ebp; sf.AddrFrame.Mode = AddrModeFlat; while ( 1 ) { // Get the next stack frame // Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOADS flag if ( !StackWalk( IMAGE_FILE_MACHINE_I386 ,GetCurrentProcess( ) ,GetCurrentThread( ) ,&sf ,context ,0 ,SymFunctionTableAccess ,SymGetModuleBase ,0 ) ) break; if ( 0 == sf.AddrFrame.Offset ) // Basic sanity check to make sure the frame is OK. Bail if not. break; sprintf( buffer, "%08X %08X ", sf.AddrPC.Offset, sf.AddrFrame.Offset ); fputs( buffer, stream ); // Get the name of the function for this stack frame entry BYTE symbolBuffer[ sizeof(SYMBOL_INFO) + 1024 ]; PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer; pSymbol->SizeOfStruct = sizeof(symbolBuffer); pSymbol->MaxNameLen = 1024; DWORD64 symDisplacement = 0; // Displacement of the input address, // relative to the start of the symbol { TCHAR szModule[MAX_PATH] = ""; DWORD section = 0, offset = 0; GetLogicalAddress( (PVOID)sf.AddrPC.Offset, szModule, sizeof(szModule), section, offset ); sprintf( buffer, "%04X:%08X %s", section, offset, szModule ); fputs( buffer, stream ); } // Get the source line for this stack frame entry IMAGEHLP_LINE lineInfo = { sizeof(IMAGEHLP_LINE) }; DWORD dwLineDisplacement; if ( SymGetLineFromAddr( GetCurrentProcess( ) ,sf.AddrPC.Offset ,&dwLineDisplacement ,&lineInfo ) ) { sprintf( buffer, "%s line %u", lineInfo.FileName, lineInfo.LineNumber ); fputs( buffer, stream ); } fputs( "\n", stream ); } fclose( stream ); } } // GenerateDump Prototype // 1. ¼Ó¼º < C/C++ < ÀÏ¹Ý < µð¹ö±ë Á¤º¸ Çü½Ä = ÇÁ·Î±×·¥ µ¥ÀÌÅͺ£À̽º(/Zi) // 2. SetUnhandledExceptionFilter( Exception_Minidump ); // 3. exceptionPointers->ExceptionRecord->ExceptionCode´Â winbase.h and winnt.h ÆÄÀÏÂüÁ¶ // (EXCEPTION_ACCESS_VIOLATION ... CONTROL_C_EXIT µî) // // ÁÖÀÇ: DBGHELP.DLL ÆÄÀÏÀÇ ¹öÀüÀº ÃÖ¼Ò 5.1.2600.0 ÀÌ»óÀ̾î¾ß ÇÑ´Ù. // (MiniDumpWriteDump ÇÔ¼ö°¡ DBGHELP.DLL¿¡ µé¾î ÀÖÀ½) LONG __stdcall GenerateDump(EXCEPTION_POINTERS* exceptionPointers) { char fileName[MAX_PATH]; SYSTEMTIME st; GetLocalTime( &st ); sprintf_s( fileName ,MAX_PATH ,"LoginServer_%4d%02d%02d_%02d%02d%02d(0x%08X 0x%08p 0x%02X 0x%04X 0x%08X).dmp" ,st.wYear ,st.wMonth ,st.wDay ,st.wHour ,st.wMinute ,st.wSecond ,exceptionPointers->ExceptionRecord->ExceptionCode ,exceptionPointers->ExceptionRecord->ExceptionAddress ,exceptionPointers->ExceptionRecord->NumberParameters ,exceptionPointers->ExceptionRecord->ExceptionInformation[0] ,exceptionPointers->ExceptionRecord->ExceptionInformation[1] ); HANDLE process = GetCurrentProcess( ); DWORD processID = GetCurrentProcessId( ); HANDLE file = CreateFile( fileName, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); MINIDUMP_EXCEPTION_INFORMATION expParam; expParam.ThreadId = GetCurrentThreadId( ); expParam.ExceptionPointers = exceptionPointers; expParam.ClientPointers = TRUE; MiniDumpWriteDump( process, processID, file, MiniDumpWithDataSegs, &expParam, NULL, NULL ); SymSetOptions( SYMOPT_DEFERRED_LOADS ); if ( SymInitialize( GetCurrentProcess( ), 0, TRUE ) ) { WriteStackDetails( exceptionPointers->ContextRecord ); } return EXCEPTION_EXECUTE_HANDLER; } // ErrorCode2String Method // // ´íÎó´úÂëת»»ÎªÏûÏ¢. // // msgBuf :´íÎóÐÅÏ¢ (»ç¿ëÈÄ LocalFree ÇÏ¿© ÁØ´Ù.) // lastError :´íÎó´úÂë // priLangId :primary language identifier // subLangId :sublanguage identifier // // ¹®ÀÚ¸Þ½ÃÁö ¾ð¾î´Â ¾Æ·¡¿Í °°ÀÌ ¼³Á¤ÇÑ´Ù. // // Primary language identifier : Sublanguage identifier : Meaning // LANG_NEUTRAL SUBLANG_NEUTRAL Language neutral // LANG_NEUTRAL SUBLANG_DEFAULT User default language // LANG_NEUTRAL SUBLANG_SYS_DEFAULT System default language DWORD ErrorCode2String(VOID** msgBuf, DWORD lastError, WORD priLangId, WORD subLangId) { // default to system source HMODULE module = NULL; DWORD bufferLength; DWORD flags; flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM; // If lastError is in the network range, load the message source. // ¸¸¾à lastError°¡ NERR_BASE ¿¡¼­ MAX_NERR Àϰæ¿ì, netmsg.dll ÀÇ // ¸Þ½ÃÁö¸¦ »ç¿ëÇÑ´Ù. (NERR_BASE, MAX_NERR´Â lmerr.h ÆÄÀÏ¿¡ Á¤ÀÇ) if ( lastError >= NERR_BASE && lastError <= MAX_NERR ) { module = LoadLibraryEx( "netmsg.dll", NULL, LOAD_LIBRARY_AS_DATAFILE ); if ( module != NULL ) { flags |= FORMAT_MESSAGE_FROM_HMODULE; } } // If lastError is in the Exception Code range, load the message source. // ¸¸¾à lastError°¡ 0xC0000000L º¸´Ù Ŭ°æ¿ì, ntdll.dllÀÇ ¸Þ½ÃÁö¸¦ »ç¿ëÇÑ´Ù. // (winbase.h, winnt.h ÆÄÀÏ¿¡ Á¤ÀÇ) if ( lastError > 0xC0000000L ) { module = LoadLibraryEx( "ntdll.dll", NULL, LOAD_LIBRARY_AS_DATAFILE ); if ( module != NULL ) { flags |= FORMAT_MESSAGE_FROM_HMODULE; } } // Call FormatMessage() to allow for message text to be acquired // from the system or from the supplied module handle. module to // get message from (NULL == system) bufferLength = FormatMessage( flags, module, lastError, MAKELANGID(priLangId, subLangId), (LPTSTR)msgBuf, 0, NULL ); // If we loaded a message source, unload it. if ( module != NULL ) { FreeLibrary( module ); } return bufferLength; } // ConsolCtrlHandler Prototype - Windows Command Processor Control Functions. BOOL WINAPI ConsolCtrlHandler(DWORD opcode) { if ( g_loginSrv ) return g_loginSrv->ConsolCtrlHandler( opcode ); else return FALSE; } // main Prototype (This method is the standard Windows program entry point.) int main(int argc, char* argv[]) { LPTOP_LEVEL_EXCEPTION_FILTER previousFilter = NULL; previousFilter = SetUnhandledExceptionFilter( GenerateDump ); cLoginSrv* loginSrv = NULL; loginSrv = new cLoginSrv( ); loginSrv->ConsoleRun( argc, argv ); SafeDelete( loginSrv ); SetUnhandledExceptionFilter( previousFilter ); return 0L; } // ServiceCtrlHandler Prototype - Windows Service Control Functions. void WINAPI ServiceCtrlHandler(DWORD opcode) { if ( g_loginSrv ) g_loginSrv->ServiceCtrlHandler( opcode ); } // ServiceMain Prototype (This method is the entry point for a service.) void WINAPI ServiceMain(DWORD argc, LPTSTR* argv) { cLoginSrv* loginSrv = NULL; loginSrv = new cLoginSrv( ); loginSrv->ServiceRun( argc, argv ); SafeDelete( loginSrv ); } // cLoginSrv Constructor. cLoginSrv::cLoginSrv(void) : mSender(NULL), mSqlWeb(NULL), mSqlAccount(NULL), mLoginProcess(NULL), mRecver(NULL) { // ´´½¨Ò»¸öÈ«¾ÖÀà¶ÔÏó. g_loginSrv = this; // ³õʼ»·¾³±äÁ¿. mUserName = NULL; mRunService = false; mEndService = false; mClose = false; mVersion = MAKEWORD(1, 0); memset( mServerAddr, 0, sizeof(mServerAddr) ); memset( mServerBroadcastRecv, 0, sizeof(mServerBroadcastRecv) ); memset( mServerBroadcastSend, 0, sizeof(mServerBroadcastSend) ); } // ~cLoginSrv Destructor. cLoginSrv::~cLoginSrv(void) { // cRecver ÀàÊÍ·Å. SafeDelete( mRecver ); // cLoginProcess ÀàÊÍ·Å. SafeDelete( mLoginProcess ); // cSQLAccount ÀàÊÍ·Å. SafeDelete( mSqlAccount ); // cSQLWeb ÀàÊÍ·Å. SafeDelete( mSqlWeb ); // cRecver ÀàÊÍ·Å. SafeDelete( mSender ); // È«¾ÖÀàÊÍ·Å. g_loginSrv = NULL; } // InstallService Method - ·þÎñ°²×°º¯Êý. bool cLoginSrv::InstallService(LPCTSTR binaryPathName, DWORD startType) { SC_HANDLE hManager(NULL); SC_HANDLE hService(NULL); bool retValue(false); TCHAR displayName[MAX_PATH]; sprintf( displayName, g_displayFmt, g_serviceName ); // Open a handle to the SC Manager database. hManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); if ( hManager != NULL ) { // The function creates a service object and adds it to the specified service control manager database. hService = CreateService( hManager, // handle to SCM database g_serviceName, // name of service to start displayName, // display name SERVICE_ALL_ACCESS, // type of access to service SERVICE_WIN32_OWN_PROCESS, // type of service startType, // when to start service SERVICE_ERROR_NORMAL, // severity of service failure binaryPathName, // name of binary file NULL, // name of load ordering group NULL, // tag identifier NULL, // array of dependency names NULL, // account name NULL ); // account password if ( hService != NULL ) { // Success CreateService retValue = true; // The function changes the optional configuration parameters of a service. SERVICE_DESCRIPTION scDesc; scDesc.lpDescription = g_description; ChangeServiceConfig2( hService, SERVICE_CONFIG_DESCRIPTION, &scDesc ); // Close the handle to the service. CloseServiceHandle( hService ); } else { // ¿À·ù¸Þ½ÃÁö Ãâ·Â - CreateService. VOID* msgBuf; if ( ErrorCode2String( &msgBuf ) ) { printf( "\nCreateService (%d): %s\n", GetLastError( ), (char*)msgBuf ); LocalFree( msgBuf ); } } } return retValue; } // UninstallService Method - ·þÎñÐ¶ÔØº¯Êý. bool cLoginSrv::UninstallService() { SC_HANDLE hManager(NULL); SC_HANDLE hService(NULL); bool retValue(false); // Open a handle to the SC Manager database. hManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); if ( hManager != NULL ) { // Open a handle to the service. hService = OpenService( hManager, g_serviceName, SERVICE_ALL_ACCESS ); if ( hService != NULL ) { // The function marks the specified service for deletion from the service control manager database. if ( DeleteService( hService ) != 0 ) { // Success DeleteService retValue = true; } else { // ¿À·ù¸Þ½ÃÁö Ãâ·Â - DeleteService VOID* msgBuf; if ( ErrorCode2String( &msgBuf ) ) { printf( "\nDeleteService (%d): %s\n", GetLastError( ), (char*)msgBuf ); LocalFree( msgBuf ); } } // Close the handle to the service. CloseServiceHandle( hService ); } else { // ¿À·ù¸Þ½ÃÁö Ãâ·Â - OpenService VOID* msgBuf; if ( ErrorCode2String( &msgBuf ) ) { printf( "\nOpenService (%d): %s\n", GetLastError( ), (char*)msgBuf ); LocalFree( msgBuf ); } } } return retValue; } // ConsolCtrlHandler Method BOOL cLoginSrv::ConsolCtrlHandler(DWORD opcode) { switch ( opcode ) { case CTRL_C_EVENT: case CTRL_BREAK_EVENT: case CTRL_CLOSE_EVENT: case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: Destroy( ); return TRUE; default: // unknown type--better pass it on. return FALSE; } } // ConsoleRun Method void cLoginSrv::ConsoleRun(DWORD argc, LPTSTR* argv) { char moduleName[MAX_PATH]; GetModuleFileName( NULL, moduleName, sizeof(moduleName) ); char drive[_MAX_DRIVE]; char directory[_MAX_DIR]; char fileName[_MAX_FNAME]; char ext[_MAX_EXT]; _splitpath( moduleName, drive, directory, fileName, ext ); if ( argc < 2 ) { // »ç¿ë¼³¸í. printf( "USAGE:\n" ); printf( "%s [/INSTALL | /UNINSTALL | /INSERT | /TEST]\n\n", fileName ); printf( " /INSTALL Creates a service object and adds it to the specified service\n" ); printf( " control manager database.\n" ); printf( " /UNINSTALL Marks the specified service for deletion from the service\n" ); printf( " control manager database.\n" ); printf( " /INSERT Upload script files to MSSQL Database.\n" ); printf( " /TEST Running the Server Program in Console mode.\n" ); printf( " OPTIONS -VERBOSE Display Debug Information.\n" ); printf( " -PACKET Display Network Information.\n" ); // 1. ¼­ºñ½º ÇÁ·Î¼¼½ºÀÇ ¸ÞÀÎ ¾²·¹µå¸¦ SCM(Service Control Manager)·Î ³Ñ±â´Â ÇÔ¼ö´Ù. // ÀÌ ÇÔ¼ö¸¦ ºÎ¸¥ ¾²·¹µå´Â Service Control Dispatcher ¾²·¹µå°¡ µÈ´Ù. // // 2. ¼­ºñ½º ÇÁ·Î±×·¥ÀÌ ½ÃÀ۵Ǹé, SCMÀº StartServiceCtrlDispatcher¸¦ ºÒ¸®±æ ±â´Ù¸®°Ô µÈ´Ù. // StartServiceCtrlDispatcher°¡ ¼º°øÇϸé, ¾²·¹µå´Â SCM ÀÌ °ü¸®Çϸç, ¼­ºñ½º°¡ ³¡³¯¶§±îÁö ¸®ÅϵÇÁö ¾Ê´Â´Ù. // ½ÇÁ¦ ¼­ºñ½ºÀÇ ½ÃÀÛÁöÁ¡Àº ÀÌ ÇÔ¼ö°¡ ³Ñ±â´Â ÀÎÀÚ°ªÀÎ ServiceMain À̶ó°í º¼¼ö ÀÖ´Ù. // // !. SERVICE_TABLE_ENTRY¸¦ µî·ÏÇØ¾ß¸¸ ServiceMainÀÌ È£Ã⠵ȴÙ. SERVICE_TABLE_ENTRY DispatchTable[]= { { g_serviceName, (LPSERVICE_MAIN_FUNCTION)ServiceMain }, { NULL, (LPSERVICE_MAIN_FUNCTION)NULL } }; printf( "\n" ); printf( "StartServiceCtrlDispatcher being called.\n" ); printf( "This may take several seconds. Please wait.\n" ); if ( !StartServiceCtrlDispatcher( DispatchTable ) ) { VOID* msgBuf; if ( ErrorCode2String( &msgBuf ) ) { printf( "\nStartServiceCtrlDispatcher (%d): %s\n", GetLastError( ), (char*)msgBuf ); LocalFree( msgBuf ); } } } else if ( !_stricmp( argv[1], "/INSTALL" ) ) { // ¼­ºñ½º·Î ¼³Ä¡¸¦ ½ÃµµÇÕ´Ï´Ù. printf( "\nInstallation to your service is initiated.\n" ); if ( InstallService( moduleName ) ) { // ¼­ºñ½º·Î ¼³Ä¡¸¦ ¿Ï·á ÇÏ¿´½À´Ï´Ù. printf( "\nInstallation to your service is completed.\n" ); } else { // ¼­ºñ½º·Î ¼³Ä¡¸¦ ¿Ï·áÇÏÁö ¸ø ÇÏ¿´½À´Ï´Ù. printf( "\nInstallation to your service is not completed.\n" ); } } else if ( !_stricmp( argv[1], "/UNINSTALL" ) ) { // ¼­ºñ½º·Î »èÁ¦¸¦ ½ÃµµÇÕ´Ï´Ù. printf( "\nDeleting your service is initiated.\n" ); if ( UninstallService( ) ) { // ¼­ºñ½º·Î »èÁ¦¸¦ ¿Ï·á ÇÏ¿´½À´Ï´Ù. printf( "\nDeleting your service is completed.\n" ); } else { // ¼­ºñ½º·Î »èÁ¦¸¦ ¿Ï·áÇÏÁö ¸ø ÇÏ¿´½À´Ï´Ù. printf( "\nDeleting our service is not completed.\n" ); } } else if ( !_stricmp( argv[1], "/INSERT" ) ) { cSQLAccount* sqlAccount = new cSQLAccount( ); int errorCount = 0; printf( "\n=============== INSERT START ===============\n" ); if ( sqlAccount->InsertCaptcha( ODBC_DSN_ACCOUNT, ODBC_UID, ODBC_PWD ) ) { printf( "\nTB_CAPTCHA table has been completed.\n" ); } else { printf( "TB_CAPTCHA table was not complete!!!\n" ); printf( "Press Any Key to Continue...\n" ); _getch( ); errorCount += 1; } printf( "\n=============== Completed ===============\n" ); printf( "\nINSERT - ERROR(=%d)\n", errorCount ); printf( "\nPress Any Key to Continue." ); _getch( ); SafeDelete( sqlAccount ); } else if ( !_stricmp( argv[1], "/TEST" ) ) { DWORD status; DWORD error; if ( SetConsoleCtrlHandler( ::ConsolCtrlHandler, TRUE ) != 0 ) { // Å×½ºÆ® ¿É¼Ç °Ë»ç. for ( DWORD i = 2; i < argc; i++ ) { if ( !_stricmp( argv[ i ], "-VERBOSE" ) ) { g_verbose = true; } else if ( !_stricmp( argv[ i ], "-FPS" ) ) { g_fps = true; } else if ( !_stricmp( argv[ i ], "-PACKET" ) ) { g_packet = true; } else if ( !_stricmp( argv[ i ], "-UDP" ) ) { g_udp = true; } else if ( !_stricmp( argv[ i ], "-UDPPACKET" ) ) { g_udpPacket = true; } else if ( !_stricmp( argv[ i ], "-UDPFROM" ) ) { g_udpFrom = true; } } // ¿ØÖÆÌ¨²âÊÔ. status = Initialization( argc, argv, &error ); if ( status == NO_ERROR ) { printf( "\nRunning the Server in Console mode.\n" ); Run( ); printf( "\nStopping the Server in Console mode.\n" ); } else { printf( "\nInitialize fail.\n" ); } SetConsoleCtrlHandler( ::ConsolCtrlHandler, FALSE ); } } } // ServiceCtrlHandler Method void cLoginSrv::ServiceCtrlHandler(DWORD opcode) { switch ( opcode ) { case SERVICE_CONTROL_STOP: // Á¾·áÇÒ ÄÚµå´Â Destroy ÇÔ¼ö¸¦ »ç¿ë. Destroy( ); // Notifies a service that it should stop. mServiceStatus.dwWin32ExitCode = 0; mServiceStatus.dwCurrentState = SERVICE_STOPPED; mServiceStatus.dwCheckPoint = 0; mServiceStatus.dwWaitHint = 0; // Updates the service control manager's status information for the calling service. SetServiceStatus( mServiceStatusHandle, &mServiceStatus ); return; case SERVICE_CONTROL_PAUSE: // Notifies a service that it should pause. mServiceStatus.dwCurrentState = SERVICE_PAUSED; break; case SERVICE_CONTROL_CONTINUE: // Notifies a paused service that it should resume. mServiceStatus.dwCurrentState = SERVICE_RUNNING; break; case SERVICE_CONTROL_INTERROGATE: // Notifies a service that it should report its current status information to the service control manager. break; case SERVICE_CONTROL_SHUTDOWN: // Notifies a service that the system is shutting down so the service can perform cleanup tasks. break; case SERVICE_CONTROL_PARAMCHANGE: // Notifies a service that its startup parameters have changed. The service should reread its startup parameters. break; case SERVICE_CONTROL_NETBINDADD: // Notifies a network service that there is a new component for binding. The service should bind to the new component. break; case SERVICE_CONTROL_NETBINDREMOVE: // Notifies a network service that a component for binding has been removed. // The service should reread its binding information and unbind from the removed component. break; case SERVICE_CONTROL_NETBINDENABLE: // Notifies a network service that a disabled binding has been enabled. // The service should reread its binding information and add the new binding. break; case SERVICE_CONTROL_NETBINDDISABLE: // Notifies a network service that one of its bindings has been disabled. // The service should reread its binding information and remove the binding. break; } // Updates the service control manager's status information for the calling service. SetServiceStatus( mServiceStatusHandle, &mServiceStatus ); } // ServiceRun Method void cLoginSrv::ServiceRun(DWORD argc, LPTSTR* argv) { DWORD status; DWORD error; mServiceStatus.dwServiceType = SERVICE_WIN32; mServiceStatus.dwCurrentState = SERVICE_START_PENDING; mServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; mServiceStatus.dwWin32ExitCode = 0; mServiceStatus.dwServiceSpecificExitCode = 0; mServiceStatus.dwCheckPoint = 0; mServiceStatus.dwWaitHint = 0; // ¼­ºñ½º Á¦¾î ó¸®ÀÚ¸¦ µî·ÏÇÑ´Ù. - ½ÇÆÐ½Ã 0¸¦ ¹Ýȯ ÇÑ´Ù. mServiceStatusHandle = RegisterServiceCtrlHandler( g_serviceName, ::ServiceCtrlHandler ); if ( mServiceStatusHandle == (SERVICE_STATUS_HANDLE)0 ) return; // Initialization code goes here. // - ÃʱâÈ­ ÇÒ ÄÚµå´Â ServiceInitialization ÇÔ¼ö¸¦ »ç¿ë // - ½ÇÆÐ½Ã NO_ERROR(0)°¡ ¾Æ´Ñ °ª¸¦ ¹Ýȯ. status = Initialization( argc, argv, &error ); // Handle error condition - ÃʱâÈ­ ½ÇÆÐ ÇÒ °æ¿ì Á¾·áÄÚµå(status)¸¦ Ç¥½ÃÇØ ÁØ´Ù. if ( status != NO_ERROR ) { mServiceStatus.dwCurrentState = SERVICE_STOPPED; mServiceStatus.dwCheckPoint = 0; mServiceStatus.dwWaitHint = 0; mServiceStatus.dwWin32ExitCode = status; mServiceStatus.dwServiceSpecificExitCode = error; // Updates the service control manager's status information for the calling service. if ( SetServiceStatus( mServiceStatusHandle, &mServiceStatus ) == FALSE ) return; } // Initialization complete - report running status. // - ÃʱâÈ­ ¿Ï·á - ¼­ºñ½º »óŸ¦ µ¿ÀÛ(RUNNING)À¸·Î ¼³Á¤. mServiceStatus.dwCurrentState = SERVICE_RUNNING; mServiceStatus.dwCheckPoint = 0; mServiceStatus.dwWaitHint = 0; // Updates the service control manager's status information for the calling service. if ( SetServiceStatus( mServiceStatusHandle, &mServiceStatus ) == FALSE ) return; // Run - ¼­ºñ½º ½ÃÀÛ. Run( ); } // Initialization Method (Stub initialization function.) // ÁÖÀ§: ÃʱâÈ­ ¹× »ý¼º ¼ø¼­¸¦ º¯°æÇÒ ¼ö ¾øÀ½. DWORD cLoginSrv::Initialization(DWORD argc, LPTSTR* argv, DWORD* error) { // WINSOCK2 ÃʱâÈ­ (¹öÀü 2.2). if ( LOBYTE( m_wsaData.wVersion ) != 2 || HIBYTE( m_wsaData.wVersion ) != 2 ) return 1L; // »ç¿ëÀÚ Á¤º¸. DWORD userNameSize = 0; DWORD userNameRetVal = 0; userNameRetVal = GetUserName( mUserName, &userNameSize ); if ( userNameRetVal == 0 && GetLastError( ) == ERROR_INSUFFICIENT_BUFFER ) { mUserName = (TCHAR*)GlobalAlloc( GPTR, userNameSize ); userNameRetVal = GetUserName( mUserName, &userNameSize ); } if ( userNameRetVal == 0 && GetLastError( ) == ERROR_INSUFFICIENT_BUFFER ) { if ( g_verbose == true ) { VOID* msgBuf; if ( ErrorCode2String( &msgBuf ) ) { printf( "\nGetUserName (%d): %s\n", GetLastError( ), (char*)msgBuf ); LocalFree( msgBuf ); } } return 1L; } // È£½ºÆ® Á¤º¸. if ( GetLocalHostInfo( ) == false ) { if ( g_verbose == true ) { VOID* msgBuf; if ( ErrorCode2String( &msgBuf ) ) { printf( "\nGetNetworkParams (%d): %s\n", GetLastError( ), (char*)msgBuf ); LocalFree( msgBuf ); } } return 1L; } // »ç¿ëÀÚ & È£½ºÆ® Á¤º¸Ãâ·Â. if ( g_verbose == true ) { printf( "\n" ); printf( "User Name............: %s \n", mUserName ); printf( "Host Name............: %s \n", mFixedInfo->HostName ); printf( "NetBIOS Scope ID.....: %s \n", mFixedInfo->ScopeId ); printf( "IP Routing Enabled...: %s \n", (mFixedInfo->EnableRouting ? "YES" : "NO") ); printf( "WINS Proxy Enabled...: %s \n", (mFixedInfo->EnableProxy ? "YES" : "NO") ); printf( "\n" ); } // ½ÇÇàȯ°æ ¼³Á¤. char drive[_MAX_DRIVE]; char dir[_MAX_DIR]; char fname[_MAX_FNAME]; char ext[_MAX_EXT]; TCHAR filename[MAX_PATH]="\0"; TCHAR directory[MAX_PATH]="\0"; GetModuleFileName( NULL, filename, sizeof(filename) ); _splitpath( filename, drive, dir, fname, ext ); char* _ext = strrchr( filename, '.' ); strcpy( _ext ? _ext : filename+strlen( filename ), ".cfg" ); sprintf( directory, "%s%s", drive, dir ); // ¼­ºñ½º & ÄÜ¼Ö & µð¹ö±× ¸ðµå ȣȯ¼º Àû¿ë. if ( GetFileAttributes( filename ) == INVALID_FILE_ATTRIBUTES ) { GetCurrentDirectory( sizeof(directory), directory ); sprintf( filename, "%s\\%s.cfg", directory, fname ); } // ½ÇÇàÆÄÀϰæ·Î Ãâ·Â. if ( g_verbose == true ) { printf( "Binary Path Name.....: %s%s%s%s \n", drive, dir, fname, ext ); printf( "Working Directory....: %s \n", directory ); printf( "Module Path Name.....: %s \n", filename ); printf( "\n" ); } FILE* stream = fopen( filename, "rt" ); char buffer[MAX_PATH]; char seps[] = " \t\n"; // ÆÄ½Ì±¸¹® Parsing. char *token; if ( stream != NULL ) { try { if ( fgets( buffer, MAX_PATH, stream ) == NULL ) throw false; token = strtok( buffer, seps ); if ( token && stricmp( token, "LOGIN_SERVER_ADDRESS(IPv4):" ) != 0 ) throw false; sprintf( mServerAddr, "%s", strtok( NULL, seps ) ); if ( fgets( buffer, MAX_PATH, stream ) == NULL ) throw false; token = strtok( buffer, seps ); if ( token && stricmp( token, "LOGIN_BROADCAST_RECV(IPv4):" ) != 0 ) throw false; sprintf( mServerBroadcastRecv, "%s", strtok( NULL, seps ) ); if ( fgets( buffer, MAX_PATH, stream ) == NULL ) throw false; token = strtok( buffer, seps ); if ( token && stricmp( token, "LOGIN_BROADCAST_SEND(IPv4):" ) != 0 ) throw false; sprintf( mServerBroadcastSend, "%s", strtok( NULL, seps ) ); if ( fgets( buffer, MAX_PATH, stream ) == NULL ) throw true; token = strtok( buffer, seps ); if ( token && stricmp( token, "LOGIN_PORT:" ) != 0 ) throw true; g_loginPort = (u_short)atoi( strtok( NULL, seps ) ); if ( fgets( buffer, MAX_PATH, stream ) == NULL ) throw true; token = strtok( buffer, seps ); if ( token && stricmp( token, "GAME_PORT:" ) != 0 ) throw true; g_gamePort = (u_short)atoi( strtok( NULL, seps ) ); if ( fgets( buffer, MAX_PATH, stream ) == NULL ) throw true; token = strtok( buffer, seps ); if ( token && stricmp( token, "LOG_PORT:" ) != 0 ) throw true; g_logPort = (u_short)atoi( strtok( NULL, seps ) ); throw true; } catch ( bool success ) { fclose( stream ); if ( success == false ) return 1L; } } else return 1L; if ( g_verbose == true ) { printf( "\nLogin Server Address..: %s", mServerAddr ); printf( "\nLogin Broadcast Recv..: %s", mServerBroadcastRecv ); printf( "\nLogin Broadcast Send..: %s", mServerBroadcastSend ); printf( "\nLogin Port............: %d", g_loginPort ); printf( "\nGame Port.............: %d", g_gamePort ); printf( "\nLog Port..............: %d", g_logPort ); printf( "\n" ); } /*-- ODBC-DNS & WINSOCK2 ³õʼ»¯ --*/ // ÉèÖù¤×÷Ŀ¼. if ( SetCurrentDirectory( directory ) == false ) return 1L; // cSender ´´½¨. mSender = new cSender( ); if ( mSender->Initialize( mServerBroadcastSend, mServerBroadcastSend, 2, 32768 ) == false ) return 1L; // cSQLWeb ´´½¨. mSqlWeb = new cSQLWeb( ); if ( mSqlWeb->Initialize( ODBC_DSN_WEB, ODBC_UID_WEB, ODBC_PWD_WEB ) == false ) return 1L; // cSQLAccount ´´½¨. mSqlAccount = new cSQLAccount( ); if ( mSqlAccount->Initialize( ODBC_DSN_ACCOUNT, ODBC_UID, ODBC_PWD ) == false ) return 1L; // cLoginProcess ´´½¨. mLoginProcess = new cLoginProcess( ); if ( mLoginProcess->Initialize( mServerAddr, T_LOGIN_CPORT ) == false ) return 1L; // cSender ´´½¨. mRecver = new cRecver( ); if ( mRecver->Initialize( mServerBroadcastRecv, g_loginPort, 2, 32768 ) == false ) return 1L; return 0L; } // Destroy Method // ÁÖÀ§: Á¾·á ¼ø¼­¸¦ º¯°æ ÇÒ ¼ö ¾øÀ½. void cLoginSrv::Destroy(void) { if ( mEndService == false ) { mEndService = true; // ¼­ºñ½º Á¾·á. if ( mRecver != NULL ) { mRecver->Shutdown( ); // cRecver Á¾·á. } if ( mLoginProcess != NULL ) { mLoginProcess->Shutdown( ); // cLoginProcess Á¾·á. } if ( mSqlAccount != NULL ) { mSqlAccount->Shutdown( ); // cSQLAccount Á¾·á. } if ( mSqlWeb != NULL ) { mSqlWeb->Shutdown( ); // cSQLWeb Á¾·á. } if ( mSender != NULL ) { mSender->Shutdown( ); // cSender Á¾·á. } if ( mUserName != NULL ) { GlobalFree( mUserName ); // ¸Þ¸ð¸® ÇØÁ¦. mUserName = NULL; } mRunService = false; // ½ÇÇàÁ¾·á. } } // Close Method void cLoginSrv::Close( ) { mClose = true; } // Run Method void cLoginSrv::Run(void) { DWORD currentTick = 0; DWORD elapsedTick = 0; // ¼­ºñ½º°¡ ½ÃÀÛ µÊ. mRunService = true; while ( mRunService ) { currentTick = GetTickCount( ); if ( mClose == true ) Destroy( ); // Áö¿¬½Ã°£ ¾à100(ms) - CPU °úºÎÈ­ ¹æÁö & ³»ºÎ µ¿±âÈ­. elapsedTick = GetTickCount( ) - currentTick; if ( elapsedTick < 100 ) { Sleep( (100 - elapsedTick) ); } } }