Files
Sun1602/Server/AuthSystem/RTT/RTTServer/Database.cpp
T
2022-10-26 12:25:11 +08:00

3281 lines
105 KiB
C++

#include "stdafx.h"
#include "Entry.h"
#include "RTTAgent.h"
#include "Database.h"
#include "MonitorProcess.h"
#include "ManagerWops.h"
#define MASTER_CHECK_TIME 30000 // master 서버에서 동접값 전송을 체크하기 위한 시간 주기
// 에러 메시지 목록
#define CPU_UPPER_LIMIT 2001 // CPU 사용률 상한 초과
#define CPU_LOWER_LIMIT 2002 // CPU 사용률 하한 미만
#define MEMORY_UPPER_LIMIT 2003 // 메모리 상한 초과
#define HDD_LEAST_LIMIT 2005 // HDD 용량 부족
#define CPU_NORMAL 2011 // CPU 장애 복구
#define MEM_NORMAL 2013 // 메모리 장애 복구
#define HDD_NORMAL 2015 // HDD 용량 장애 복구
#define USERCOUNT_GAPOVER 3001 // 동접수 폭증
#define USERCOUNT_GAPLOWER 3002 // 동접수 폭감
#define MASTER_SERVER_ERROR 3003 // Master 서버 장애 발생
#define MASTER_SERVER_SUCCESS 3013 // Master 서버 장애 복구
#define RTTS_NOT_RESPONSE 4001 // RTTS 응답 없음
#define RTTA_NOT_RESPONSE 4002 // RTTA 응답 없음
#define RTTA_RESPONSE 4012 // RTTA 응답 없음
#define PROCESS_SHUTDOWN 5001 // Process 중지
#define PROCESS_STARTUP 5011 // Process 중지 장애 복구
#define SUPPLYMONEY_ERROR 6001 // 통화량 장애
#define PATCH_FTPCONNECT_FAIL 7001 // 패치 중 FTP 연결 실패
#define PATCH_DOWNLOAD_FAIL 7002 // 패치 중 파일 다운로드 실패
#define PATCH_FILESEARCH_FAIL 7003 // 패치 중 파일찾기 실패
#define PATCH_PROCESSRUNNING 7004 // 패치 대상 프로세스가 실행중
#define PATCH_SUCCESS 7777 // 패치 대상 성공
#define WEB_CONNECT_FAIL 8001 // 웹 서버 연결 실패
#define WEB_CONNECT_RESTORE 8002 // 웹 서버 연결 성공
#define WEB_REQUEST_FAIL 8003 // HTTP 요청 실패
#define WEB_REQUEST_RESTORE 8004 // HTTP 요청 성공
// 에러 문자열 목록
#define MSG_CPU_UPPER_LIMIT "(CPU = %d%%)"
#define MSG_CPU_LOWER_LIMIT "(CPU = %d%%)"
#define MSG_MEMORY_UPPER_LIMIT "(Memory = %d/%dMB (%d%% using))"
#define MSG_HDD_LEAST_LIMIT "(HDD = %d/%dMB (%d%% using))"
#define MSG_USERCOUNT_GAPOVER "(%d → %d)"
#define MSG_USERCOUNT_GAPLOWER "(%d → %d)"
#define MSG_RTTA_NOT_RESPONSE ""
#define MSG_RTTA_RESPONSE ""
#define MSG_PROCESS_SHUTDOWN "(%s)"
#define MSG_SUPPLYMONEY_ERROR "(PerGetMoney = %I64d, CurGetMoney = %I64d, Rate of Increase = %d%%)"
#define MSG_WEB_CONNECT_FAIL "(커넥션 장애)"
#define MSG_WEB_CONNECT_RESTORE "(커넥션 장애 복구)"
#define MSG_WEB_REQUEST_FAIL "(Page Fault 장애)"
#define MSG_WEB_REQUEST_RESTORE "(Page Fault 장애 복구)"
#define CONNECT_STRING "DSN=%s;Initial Catalog=%s;User ID=%s;Password=%s;Max Pool Size=100;Min Pool Size=30;Pooling=yes;"
void Database::CallbackErrorDBC( eXtreme::DBC* dbc, HRESULT result, _bstr_t msg, _bstr_t src, _bstr_t desc )
{
if(result==E_FAIL)
{
dbc->m_lastQuery = "";
dbc->Close();
}
UINT uiQueryLength = dbc->m_lastQuery.length();
OutputDebug( "[DBC Error]\n" );
OutputDebug( "Code = %08lx\n", result );
OutputDebug( "Means = %s(%d)\n", ( char* )msg, dbc->m_lastQuery.length() );
/*
OutputDeubug에 buffer는 4096이므로 query가 크기를 넘어서는 것을 방지한다.
*/
if(uiQueryLength<=4000)
{
OutputDebug( "Query = %s\n", ( char* )dbc->m_lastQuery );
}
else
{
char szQuery[4096] = {0, };
strncpy(szQuery, (char*)dbc->m_lastQuery, 4000);
OutputDebug( "Query = %s\n", ( char* )szQuery );
}
OutputDebug( "Description = %s\n", ( char* )desc );
}
void Database::CallbackErrorRecordSet( eXtreme::RecordSet* recordset,
HRESULT result, _bstr_t msg, _bstr_t src, _bstr_t desc )
{
if(result==E_FAIL)
{
recordset->m_lastQuery = "";
}
OutputDebug( "[RecordSet Error]\n" );
OutputDebug( "Code = %08lx\n", result );
OutputDebug( "Means = %s\n", ( char* )msg );
OutputDebug( "Query = %s\n", ( char* )recordset->m_lastQuery );
OutputDebug( "Description = %s\n", ( char* )desc );
}
class TB_ServerInfo : public eXtreme::RecordSet
{
public:
ServerInfo record;
public:
TB_ServerInfo()
{
m_callbackError = Database::CallbackErrorRecordSet;
BindVariable( record.nv_ChannelName, "nv_ChannelName" );
BindVariable( &record.ti_WorldID, "ti_WorldID" );
BindVariable( &record.ti_ChannelID, "ti_ChannelID" );
BindVariable( &record.ti_ServerType, "ti_ServerType" );
BindVariable( &record.ti_ServerID, "ti_ServerID" );
BindVariable( record.nv_ServerName, "nv_ServerName" );
BindVariable( record.vc_IP, "vc_IP" );
BindVariable( record.i_Port, "i_Port" );
BindVariable( record.vc_InnerIP, "vc_InnerIP" );
BindVariable( record.i_InnerPort, "i_InnerPort" );
}
};
class T_Manager : public eXtreme::RecordSet
{
public:
AdminInfo record;
public:
T_Manager()
{
m_callbackError = Database::CallbackErrorRecordSet;
BindVariable( record.UserID, "UserID" );
BindVariable( &record.LV, "LV" );
BindVariable( &record.IpAddr, "IpAddr" );
}
};
class TB_WarningCanon : public eXtreme::RecordSet
{
public:
WarningCanon record;
public:
TB_WarningCanon()
{
m_callbackError = Database::CallbackErrorRecordSet;
BindVariable( &record.ti_WorldID, "ti_WorldID" );
BindVariable( &record.ti_ChannelID, "ti_ChannelID" );
BindVariable( &record.ti_ServerType, "ti_ServerType" );
BindVariable( &record.ti_ServerID, "ti_ServerID" );
BindVariable( &record.i_ConnectCountUnderGap, "i_ConnectCountUnderGap" );
BindVariable( &record.i_ConnectCountOverGap, "i_ConnectCountOverGap" );
BindVariable( &record.i_CpuUpperLimit, "i_CpuUpperLimit" );
BindVariable( &record.i_CpuUpperFrequency, "i_CpuUpperFrequency" );
BindVariable( &record.i_CpuLowerLimit, "i_CpuLowerLimit" );
BindVariable( &record.i_CpuLowerFrequency, "i_CpuLowerFrequency" );
BindVariable( &record.i_MemoryUpperLimit, "i_MemoryUpperLimit" );
BindVariable( &record.i_MemoryUpperFrequency, "i_MemoryUpperFrequency" );
BindVariable( &record.i_HDDRemainder, "i_HDDRemainder" );
}
};
class TB_UpdateTime : public eXtreme::RecordSet
{
public:
UpdateTime record;
public:
TB_UpdateTime()
{
m_callbackError = Database::CallbackErrorRecordSet;
BindVariable( &record.ti_ConnectCountUpdateTime, "ti_ConnectCountUpdateTime" );
BindVariable( &record.ti_ResourceUpdateTime, "ti_ResourceUpdateTime" );
BindVariable( &record.ti_WopsRelationUpdateTime, "ti_WopsRelationUpdateTime" );
BindVariable( &record.ti_MoneyUpdateTIme, "ti_MoneyUpdateTIme" );
BindVariable( &record.ti_MoneyGap, "ti_MoneyGap" );
}
};
class TB_ServerProcess : public eXtreme::RecordSet
{
public:
ServerProcess record;
public:
TB_ServerProcess()
{
m_callbackError = Database::CallbackErrorRecordSet;
BindVariable( &record.i_ProcessIndex , "i_ProcessIndex" );
BindVariable( &record.ti_WorldID , "ti_WorldID" );
BindVariable( &record.ti_ChannelID , "ti_ChannelID" );
BindVariable( &record.ti_ServerType , "ti_ServerType" );
BindVariable( &record.ti_ServerID , "ti_ServerID" );
BindVariable( &record.ti_ServerTypeForPatch, "ti_ServerTypeForPatch" );
BindVariable( &record.vc_ProcessName , "vc_ProcessName" );
BindVariable( &record.vc_AbsolutePath , "vc_AbsolutePath" );
}
};
class TB_WebServerRequestTestURL : public eXtreme::RecordSet
{
public:
WebServerRequestTestURL record;
public:
TB_WebServerRequestTestURL()
{
m_callbackError = Database::CallbackErrorRecordSet;
BindVariable( &record.vc_URL , "vc_URL" );
}
};
Database::Database()
: m_svrInfoRTTS( NULL ), m_eventKill( INVALID_HANDLE_VALUE ), m_gapConnectCount(0), m_gapResource(0),
m_gapWopsRelation(0), m_stdMoneyGap(0), m_flagReconnectDB( true )
{
}
Database::~Database()
{
}
bool Database::Create()
{
m_eventKill = ::CreateEvent( 0, 0, 0, 0 );
m_flagReconnectDB = !Initialize();
Start();
// DB 연결에 실패하였는지를 반환한다.
return ( m_flagReconnectDB == false );
}
void Database::Destroy()
{
// Thread를 종료시킨다.
::SetEvent( m_eventKill );
if( WaitForTerminate( 1000 ) == false )
Terminate( 0 );
::CloseHandle( m_eventKill );
m_eventKill = INVALID_HANDLE_VALUE;
// Data를 Release한다.
Finalize();
m_flagReconnectDB = false;
}
bool Database::Initialize()
{
OutputDebug("[Database::Initialize] Start\n");
m_flagReconnectDB = true;
// ★ Database에 연결한다. 일단은 ODBC의 DSN을 사용해야한다.
// IP로 직접 연결은 왜 안되는걸까;;;
{
//LPCSTR szConnStr = "Provider=sqloledb;Data Source=10.101.203.201,6279;Network Library=DBMSSOCN;Initial Catalog=WopsRTTSunConnectLogKor;User ID=wops;Password=@wops!1;";
char dsn[20] = {0, };
char initialDB[40] = {0, };
char account[20] = {0, };
char password[20] = {0, };
::GetPrivateProfileString( "DBSetting", "DSN", "WopsAdmin", dsn, 20, SERVERINFO_FILENAME );
::GetPrivateProfileString( "DBSetting", "InitialDB", "WopsRTTSunConnectLogKor", initialDB, 40, SERVERINFO_FILENAME );
::GetPrivateProfileString( "DBSetting", "Account", "sa", account, 20, SERVERINFO_FILENAME );
::GetPrivateProfileString( "DBSetting", "Password", "rmfnqdnpdj", password, 20, SERVERINFO_FILENAME );
m_dbcWops.m_callbackError = CallbackErrorDBC;
memset(m_lpConnectString, 0x00, 256);
sprintf(m_lpConnectString, CONNECT_STRING, dsn, initialDB, account, password);
if( m_dbcWops.Open( dsn, initialDB, account, password, 30 ) == false )
{
OutputDebug( "Cannot connect to Database(WopsAdmin)\n" );
return false;
}
m_dbcWopsExternal.m_callbackError = CallbackErrorDBC;
if( m_dbcWopsExternal.Open( dsn, initialDB, account, password ) == false )
{
OutputDebug( "Cannot connect to Database(WopsAdmin)\n" );
return false;
}
OutputDebug( "Connected Database(WopsAdmin)\n" );
}
// try
// {
// 서버 목록
{
TB_ServerInfo record;
int count = 0;
m_dbcWops.Query( &record, "SELECT nv_ChannelName, ti_WorldID, ti_ChannelID, ti_ServerType, ti_ServerID, "
"nv_ServerName, vc_IP, i_Port, vc_InnerIP, i_InnerPort FROM TB_ServerInfo" );
while( record.IsEndRecord() == false )
{
count++;
InsertServerInfo( record.record );
InsertResoureTable( record.record.ti_WorldID, record.record.ti_ChannelID, record.record.ti_ServerType, record.record.ti_ServerID, record.record.vc_InnerIP );
// 프로세스 감시 목록
{
TB_ServerProcess recordProcess;
char tmp[127] = {0, };
sprintf( tmp, "{call USP_GetServerProcess( %d, %d, %d, %d )}",
record.record.ti_WorldID, record.record.ti_ChannelID,
record.record.ti_ServerType, record.record.ti_ServerID );
m_dbcWops.Query( &recordProcess, tmp );
while( recordProcess.IsEndRecord() == false )
{
MonitorProcess::Instance()->AddProcess( recordProcess.record.ti_WorldID,
recordProcess.record.ti_ChannelID,
recordProcess.record.ti_ServerType,
recordProcess.record.ti_ServerID,
record.record.vc_InnerIP,
recordProcess.record.ti_ServerTypeForPatch,
recordProcess.record.vc_ProcessName,
recordProcess.record.vc_AbsolutePath );
recordProcess.Next();
}
}
// 경고 기준 테이블
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexWarningCanon );
TB_WarningCanon recordCanon;
char tmp[256] = {0, };
sprintf( tmp, "{call USP_GetWarningCanonPerServer( %d, %d, %d, %d )}",
record.record.ti_WorldID, record.record.ti_ChannelID,
record.record.ti_ServerType, record.record.ti_ServerID );
m_dbcWops.Query( &recordCanon, tmp );
if( recordCanon.IsEndRecord() == false ) // 각 서버당 1개의 기준값을 갖는다.
{
WarningCanon* canon = new WarningCanon;
memcpy( canon, &recordCanon.record, sizeof( WarningCanon ) );
m_listWarningCanon.push_back( canon );
}
}
// 배틀서버 목록
if( record.record.ti_ServerType == 3 && record.record.ti_ServerID == 1 )
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexBattleZone );
{ // 1 - 헌팅방
BattleZoneInfo* info = new BattleZoneInfo;
info->ti_worldID = record.record.ti_WorldID;
info->ti_channelID = record.record.ti_ChannelID;
info->ti_zoneType = 1;
info->i_roomCount = 0;
m_listBattleZoneInfo.push_back( info );
}
{ // 2 - 미션방
BattleZoneInfo* info = new BattleZoneInfo;
info->ti_worldID = record.record.ti_WorldID;
info->ti_channelID = record.record.ti_ChannelID;
info->ti_zoneType = 2;
info->i_roomCount = 0;
m_listBattleZoneInfo.push_back( info );
}
{ // 3 - PVP존
BattleZoneInfo* info = new BattleZoneInfo;
info->ti_worldID = record.record.ti_WorldID;
info->ti_channelID = record.record.ti_ChannelID;
info->ti_zoneType = 3;
info->i_roomCount = 0;
m_listBattleZoneInfo.push_back( info );
}
/*
[2006.04.26] modify by guiun
경쟁 헌팅방 추가
*/
{ // 4 - 경쟁헌팅존
BattleZoneInfo* info = new BattleZoneInfo;
info->ti_worldID = record.record.ti_WorldID;
info->ti_channelID = record.record.ti_ChannelID;
info->ti_zoneType = 4;
info->i_roomCount = 0;
m_listBattleZoneInfo.push_back( info );
}
}
record.Next();
}
OutputDebug( "Server list updated(Total %d).\n", count );
}
// 관리자 목록
{
T_Manager record;
int count = 0;
m_dbcWops.Query( &record, "SELECT UserID, LV, IpAddr FROM T_Manager" );
while( record.IsEndRecord() == false )
{
InsertAdminInfo( record.record );
record.Next();
count++;
}
OutputDebug( "Administrator list updated(Total %d).\n\n", count );
}
// Update 주기
GetUpdateTime();
// }
// catch( eXtreme::ExceptionDBC& )
// {
// return false;
// }
Entry::Instance()->ServiceStartUp();
m_flagReconnectDB = false;
OutputDebug("[Database::Initialize] End\n");
return true;
}
void Database::Finalize()
{
OutputDebug("[Database::Finalize] Start\n");
Entry::Instance()->ServiceTerminate();
// 서버 목록 삭제
{
ServerInfo* info = NULL;
for(ListServerInfo::iterator iter = m_listServerInfo.begin() ; iter != m_listServerInfo.end() ; iter++ )
{
info = *iter;
delete info;
}
m_listServerInfo.clear();
}
// 통화량 목록 삭제
{
SupplyMoney* info = NULL;
for(ListSupplyMoney::iterator iter = m_listSupplyMoney.begin() ; iter != m_listSupplyMoney.end() ; iter++ )
{
info = *iter;
delete info;
}
m_listSupplyMoney.clear();
}
// 게임 통게 목록 삭제
{
GameStatistics* info = NULL;
for(ListGameStatistics::iterator iter = m_listGameStatistics.begin() ; iter != m_listGameStatistics.end() ; iter++ )
{
info = *iter;
delete info;
}
m_listGameStatistics.clear();
}
// 배틀존 목록 삭제
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexBattleZone );
BattleZoneInfo* info = NULL;
for(ListBattleZoneInfo::iterator iter = m_listBattleZoneInfo.begin() ; iter != m_listBattleZoneInfo.end() ; iter++ )
{
info = *iter;
delete info;
}
m_listBattleZoneInfo.clear();
}
// 관리자 목록 삭제
{
AdminInfo* info = NULL;
for(ListAdminInfo::iterator iter = m_listAdminInfo.begin() ; iter != m_listAdminInfo.end() ; iter++ )
{
info = *iter;
delete info;
}
m_listAdminInfo.clear();
}
// 경고 기준 테이블 삭제
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexWarningCanon );
WarningCanon* info = NULL;
for(ListWarningCanon::iterator iter = m_listWarningCanon.begin() ; iter != m_listWarningCanon.end() ; iter++ )
{
info = *iter;
delete info;
}
m_listWarningCanon.clear();
}
// System Resource 목록 삭제
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexSystemResource );
ResourceInfo* info = NULL;
for(ListSystemResource::iterator iter = m_listSystemResource.begin() ; iter != m_listSystemResource.end() ; iter++ )
{
info = *iter;
delete info;
}
m_listSystemResource.clear();
}
// Patch Key 목록 삭제
ClearPatchKeyAll();
/*
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexPatchKey );
ListPatchKey::iterator iter;
PatchKey* info;
for( iter = m_listPatchKey.begin() ; iter != m_listPatchKey.end() ; iter++ )
{
info = *iter;
delete info;
}
m_listPatchKey.clear();
}
*/
m_dbcWops.Close();
m_dbcWopsExternal.Close();
m_flagReconnectDB = true;
OutputDebug("[Database::Finalize] End\n");
}
// 2006. 7. 13 김종호
// void 타입 리턴을 bool로 수정
bool Database::QueryExternal( char* queryStr, ... )
{
eXtreme::Guard < eXtreme::Mutex > guard( m_mutexDBCEx );
va_list args;
char buffer[1024] = {0, };
va_start( args, queryStr );
vsprintf( buffer, queryStr, args );
va_end( args );
// m_dbcWopsExternal.Query( 0, buffer );
if( !m_dbcWopsExternal.Query( 0, buffer ) )
{
return false;
}
return true;
}
// 2006. 7. 13 김종호
// void 타입 리턴을 bool로 수정
bool Database::QueryExternal2( char* queryStr, ... )
{
//eXtreme::Guard < eXtreme::Mutex > guard( m_mutexDBCEx );
va_list args;
char buffer[2048] = {0, };
va_start( args, queryStr );
vsprintf( buffer, queryStr, args );
va_end( args );
{
// eXtreme::DBC dbConn;
// dbConn.Open(m_lpConnectString);
// dbConn.m_callbackError = Database::CallbackErrorDBC;
// dbConn.Query( 0, buffer );
eXtreme::DBC dbConn;
if( !dbConn.Open(m_lpConnectString) )
return false;
dbConn.m_callbackError = Database::CallbackErrorDBC;
if( !dbConn.Query( 0, buffer ) )
return false;
}
return true;
}
// 2006. 7. 24 김종호 쿼리함수 추가
int Database::QueryArmorKit(int iHackLogID, int iHackType, int iGuid, char* pIP, int iHookType, char* pDllName,
int iOrdinal, char* pApiName, DWORD_PTR OriginalAddr, DWORD_PTR CurrentAddr,
DWORD_PTR DetourAddr, char* pOriginalOpcodes, char* pCurrentOpcodes,
char* pDetourAddrOpcodes, DWORD_PTR ValidStartAddr, DWORD_PTR ValidEndAddr, int iErrorCode)
{
eXtreme::DBC dbConn;
eXtreme::RecordSet rec;
if( !dbConn.Open(m_lpConnectString) ) return false;
dbConn.m_callbackError = Database::CallbackErrorDBC;
rec.m_callbackError = Database::CallbackErrorRecordSet;
int iLogID = 0;
char pOriginalAddr[20] = {0, };
char pCurrentAddr[20] = {0, };
char pDetourAddr[20] = {0, };
char pValidStartAddr[20] = {0, };
char pValidEndAddr[20] = {0, };
sprintf(pOriginalAddr , "%d", OriginalAddr);
sprintf(pCurrentAddr , "%d", CurrentAddr);
sprintf(pDetourAddr , "%d", DetourAddr);
sprintf(pValidStartAddr , "%d", ValidStartAddr);
sprintf(pValidEndAddr , "%d", ValidEndAddr);
/*-------- char 문자열이 "" 일 경우 DB의 NULL과는 다르므로 ---------------*/
/*-------- 문자열 길이를 체크해서 0바이트면 빈 문자 한개를 넣어준다 ------*/
if( !pIP || !strlen(pIP) )
pIP = " ";
if( !pDllName || !strlen(pDllName) )
pDllName = " ";
if( !pApiName || !strlen(pApiName) )
pApiName = " ";
if( !pOriginalOpcodes || !strlen(pOriginalOpcodes) )
pOriginalOpcodes = " ";
if( !pCurrentOpcodes || !strlen(pCurrentOpcodes) )
pCurrentOpcodes = " ";
if( !pDetourAddrOpcodes || !strlen(pDetourAddrOpcodes) )
pDetourAddrOpcodes = " ";
/*----------------------------------------------------- 여기까지... :-) --*/
// LogID return 값을 받는다.
rec.BindParameter(&iLogID, "", adInteger, adParamReturnValue, sizeof(int), "");
// input parameter bind
rec.BindParameter(NULL, "@HackLogID" , adInteger, adParamInput, 4 , _bstr_t(iHackLogID));
rec.BindParameter(NULL, "@HackType" , adInteger, adParamInput, 4 , _bstr_t(iHackType));
rec.BindParameter(NULL, "@Guid" , adInteger, adParamInput, 4 , _bstr_t(iGuid));
rec.BindParameter(NULL, "@IP" , adVarChar, adParamInput, (long)strlen(pIP) , _bstr_t(pIP));
rec.BindParameter(NULL, "@HookType" , adInteger, adParamInput, 4 , _bstr_t(iHookType));
rec.BindParameter(NULL, "@DllName" , adVarChar, adParamInput, (long)strlen(pDllName) , _bstr_t(pDllName));
rec.BindParameter(NULL, "@Ordinal" , adInteger, adParamInput, 4 , _bstr_t(iOrdinal));
rec.BindParameter(NULL, "@ApiName" , adVarChar, adParamInput, (long)strlen(pApiName) , _bstr_t(pApiName));
rec.BindParameter(NULL, "@OriginalAddr" , adVarChar, adParamInput, (long)strlen(pOriginalAddr) , _bstr_t(pOriginalAddr));
rec.BindParameter(NULL, "@CurrentAddr" , adVarChar, adParamInput, (long)strlen(pCurrentAddr) , _bstr_t(pCurrentAddr));
rec.BindParameter(NULL, "@DetourAddr" , adVarChar, adParamInput, (long)strlen(pDetourAddr) , _bstr_t(pDetourAddr));
rec.BindParameter(NULL, "@OriginalOpcodes" , adVarChar, adParamInput, (long)strlen(pOriginalOpcodes) , _bstr_t(pOriginalOpcodes));
rec.BindParameter(NULL, "@CurrentOpcodes" , adVarChar, adParamInput, (long)strlen(pCurrentOpcodes) , _bstr_t(pCurrentOpcodes));
rec.BindParameter(NULL, "@DetourAddrOpcodes", adVarChar, adParamInput, (long)strlen(pDetourAddrOpcodes) , _bstr_t(pDetourAddrOpcodes));
rec.BindParameter(NULL, "@ValidStartAddr" , adVarChar, adParamInput, (long)strlen(pValidStartAddr) , _bstr_t(pValidStartAddr));
rec.BindParameter(NULL, "@ValidEndAddr" , adVarChar, adParamInput, (long)strlen(pValidEndAddr) , _bstr_t(pValidEndAddr));
rec.BindParameter(NULL, "@ErrorCode" , adInteger, adParamInput, 4 , _bstr_t(iErrorCode));
// call storedProcedure
dbConn.CallStoredProcedure(&rec, "USP_AddHackLog_HOOK_DETECT");
//eXtreme::DBC dbConn;
//if( !dbConn.Open(m_lpConnectString) )
// return false;
//dbConn.m_callbackError = Database::CallbackErrorDBC;
//if( !dbConn.Query( 0, buffer ) )
// return false;
if( dbConn.GetState() == adStateOpen )
{
dbConn.Close();
}
return iLogID;
}
DWORD Database::GetURLList(short worldID, short channelID, short serverType, short serverID, WebServerRequestTestURL wzURLList[])
{
TB_WebServerRequestTestURL record;
char tmp[127] = {0, };
sprintf( tmp, "{call USP_GetWebServerRequestTestURL( %d, %d, %d, %d )}", worldID, channelID, serverType, serverID );
m_dbcWops.Query( &record, tmp );
DWORD dwCount = 0;
while( record.IsEndRecord() == false )
{
wcscpy( wzURLList[dwCount++].vc_URL, record.record.vc_URL );
record.Next();
}
return dwCount;
}
DWORD Database::QueryConnectRequestState( short worldID, short channelID, short serverType, short serverID, DWORD dwParentHistoryIndex, bool bError, DWORD dwErrorCode )
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexWebRequest );
char dateTime[128] = {0 }; // 현재 날짜
char szBuffer[96] = {0, }; // 장애 or 복구 저장시에 추가할 메시지
DWORD dwRetValue = 0;
DWORD dwWarning = 0;
DWORD key = UID( worldID, channelID, serverType, serverID ); // 서버 키를 구한다
{// 현재 날짜
SYSTEMTIME sysTime;
::GetLocalTime( &sysTime );
sprintf( dateTime, "%d-%02d-%02d %02d:%02d:%02d", sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond );
}
if( bError )
{
m_MapWebRequest[key] = WEB_CONNECT_FAIL; // 맵에 에러정보 저장
dwWarning = WEB_CONNECT_FAIL;
sprintf(&szBuffer[0], MSG_WEB_CONNECT_FAIL);
}
else
{
if( 0 == dwErrorCode )
{
m_MapWebRequest.erase(key); // 맵에서 에러정보 삭제
}
else
{
m_MapWebRequest[key] = WEB_REQUEST_FAIL; // 맵에 에러정보 저장
}
dwWarning = WEB_CONNECT_RESTORE;
sprintf(&szBuffer[0], MSG_WEB_CONNECT_RESTORE);
}
eXtreme::DBC dbConn;
eXtreme::RecordSet rec;
// Return Value Bind
rec.BindParameter(&dwRetValue, "", adInteger, adParamReturnValue, sizeof(int), "");
// input parameter bind
rec.BindParameter(NULL, "@WorldID" , adTinyInt, adParamInput, 1 , _bstr_t(worldID ));
rec.BindParameter(NULL, "@ChannelID" , adTinyInt, adParamInput, 1 , _bstr_t(channelID ));
rec.BindParameter(NULL, "@ServerType" , adTinyInt, adParamInput, 1 , _bstr_t(serverType));
rec.BindParameter(NULL, "@ServerID" , adTinyInt, adParamInput, 1 , _bstr_t(serverID ));
rec.BindParameter(NULL, "@HitchDetailID" , adInteger, adParamInput, 4 , _bstr_t(dwWarning ));
rec.BindParameter(NULL, "@nv_Message" , adVarChar, adParamInput, (long)strlen(szBuffer), _bstr_t(szBuffer ));
rec.BindParameter(NULL, "@dt_RegisterDate" , adVarChar, adParamInput, (long)strlen(dateTime), _bstr_t(dateTime ));
rec.BindParameter(NULL, "@ProcessName" , adVarChar, adParamInput, 1 , _bstr_t(" " ));
rec.BindParameter(NULL, "@AbsolutePath" , adVarChar, adParamInput, 1 , _bstr_t(" " ));
rec.BindParameter(NULL, "@ParentHistoryIDX" , adInteger, adParamInput, 4 , _bstr_t(dwParentHistoryIndex));
if( !dbConn.Open(m_lpConnectString) )
{
OutputDebug("[QueryConnectRequestState] DB Not Connect!\n");
return 0;
}
dbConn.m_callbackError = Database::CallbackErrorDBC;
rec.m_callbackError = Database::CallbackErrorRecordSet;
// call storedProcedure
m_dbcWops.CallStoredProcedure(&rec, "USP_AddWarningHistoryForResource");
return ( true == bError ? dwRetValue : 0 );
}
DWORD Database::QueryWebPageRequestState( short worldID, short channelID, short serverType, short serverID, DWORD dwParentHistoryIndex, bool bError )
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexWebRequest );
char dateTime[128] = {0 }; // 현재 날짜
char szBuffer[96] = {0, }; // 장애 or 복구 저장시에 추가할 메시지
DWORD dwRetValue = 0;
DWORD dwWarning = 0;
DWORD key = UID( worldID, channelID, serverType, serverID ); // 서버 키를 구한다
{// 현재 날짜
SYSTEMTIME sysTime;
::GetLocalTime( &sysTime );
sprintf( dateTime, "%d-%02d-%02d %02d:%02d:%02d", sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond );
}
if( bError )
{
m_MapWebRequest[key] = WEB_REQUEST_FAIL; // 맵에 에러정보 저장
dwWarning = WEB_REQUEST_FAIL;
sprintf(&szBuffer[0], MSG_WEB_REQUEST_FAIL);
}
else
{
m_MapWebRequest.erase(key); // 맵에서 에러정보 삭제
dwWarning = WEB_REQUEST_RESTORE;
sprintf(&szBuffer[0], MSG_WEB_REQUEST_RESTORE);
}
eXtreme::DBC dbConn;
eXtreme::RecordSet rec;
// Return Value Bind
rec.BindParameter(&dwRetValue, "", adInteger, adParamReturnValue, sizeof(int), "");
// input parameter bind
rec.BindParameter(NULL, "@WorldID" , adTinyInt, adParamInput, 1 , _bstr_t(worldID ));
rec.BindParameter(NULL, "@ChannelID" , adTinyInt, adParamInput, 1 , _bstr_t(channelID ));
rec.BindParameter(NULL, "@ServerType" , adTinyInt, adParamInput, 1 , _bstr_t(serverType));
rec.BindParameter(NULL, "@ServerID" , adTinyInt, adParamInput, 1 , _bstr_t(serverID ));
rec.BindParameter(NULL, "@HitchDetailID" , adInteger, adParamInput, 4 , _bstr_t(dwWarning ));
rec.BindParameter(NULL, "@nv_Message" , adVarChar, adParamInput, (long)strlen(szBuffer), _bstr_t(szBuffer ));
rec.BindParameter(NULL, "@dt_RegisterDate" , adVarChar, adParamInput, (long)strlen(dateTime), _bstr_t(dateTime ));
rec.BindParameter(NULL, "@ProcessName" , adVarChar, adParamInput, 1 , _bstr_t(" " ));
rec.BindParameter(NULL, "@AbsolutePath" , adVarChar, adParamInput, 1 , _bstr_t(" " ));
rec.BindParameter(NULL, "@ParentHistoryIDX" , adInteger, adParamInput, 4 , _bstr_t(dwParentHistoryIndex));
if( !dbConn.Open(m_lpConnectString) )
{
OutputDebug("[QueryWebPageRequestState] DB Not Connect!\n");
return 0;
}
dbConn.m_callbackError = Database::CallbackErrorDBC;
rec.m_callbackError = Database::CallbackErrorRecordSet;
// call storedProcedure
m_dbcWops.CallStoredProcedure(&rec, "USP_AddWarningHistoryForResource");
return ( true == bError ? dwRetValue : 0 );
}
void Database::SendErrorNotifyNTF(DWORD dwWorldID, DWORD dwChannelID, DWORD dwServerType, DWORD dwServerID, DWORD warningID, char* dateTime, char* msg, ... )
{
// if( m_svrInfoRTTS == NULL ) return;
//
//#define NOTIFY_WSDL "http://%s/RTT/SUN/WebService/wsRTTUser/wsConnect.asmx?wsdl"
//
// char buffer[256];memset(buffer, 0x00, 256);
// {
// va_list args;
// va_start( args, msg );
// vsprintf( buffer, msg, args );
// va_end( args );
// }
// char wsdl_uri[128];
// sprintf(wsdl_uri, NOTIFY_WSDL, ManagerWSSession::Instance()->getIP());
//
// SOAPMessageFactory soap;
//
// soap.initalize(wsdl_uri, 80);
// soap.setSoapAction("WOPS.RTT.WebSerivce/wpTriggerNotify2");
//
// soap.addParameter("worldID" , dwWorldID );
// soap.addParameter("channelID" , dwChannelID );
// soap.addParameter("serverType" , dwServerType );
// soap.addParameter("serverID" , dwServerID );
// soap.addParameter("warningDetailID" , warningID );
// soap.addParameter("message" , buffer );
// soap.addParameter("date" , dateTime );
// soap.addParameter("gameID" , ManagerWSSession::Instance()->getGameID());
// soap.addParameter("serviceID" , ManagerWSSession::Instance()->getServiceID());
//
// ManagerWSSession::Instance()->putMessage(soap.invoke());
//
// OutputDebug( "[Error Notify to WOPS] %d.%d.%d.%d : warning=%d[%s]%s\n",
// dwWorldID,
// dwChannelID,
// dwServerType,
// dwServerID,
// warningID,
// buffer,
// dateTime);
va_list args;
char buffer[256] = {0, };
MSG_RTTW_ERRORNOTIFY_NTF sendPacket;
va_start( args, msg );
vsprintf( buffer, msg, args );
va_end( args );
sendPacket.dwWorldID = dwWorldID;
sendPacket.dwChannelID = dwChannelID;
sendPacket.dwServerType = dwServerType;
sendPacket.dwServerID = dwServerID;
sendPacket.dwWarningDetailID = warningID;
::MultiByteToWideChar( CP_ACP, 0, buffer, -1, sendPacket.szMessage, 120 );
::MultiByteToWideChar( CP_ACP, 0, dateTime, -1, sendPacket.szDateTime, 20 );
if(dwWorldID==0 && dwChannelID==0 && dwServerType==0 && dwServerID==0){
OutputDebug( "[Error Notify to WOPS] %d.%d.%d.%d : warning=%d\n%s %s\n",
sendPacket.dwWorldID,
sendPacket.dwChannelID,
sendPacket.dwServerType,
sendPacket.dwServerID,
sendPacket.dwWarningDetailID,
buffer,
dateTime);
}
else{ // 연결 유지로 설정된 Wops session으로 보내야 한다.
Wops* wops = ManagerWops::Instance()->GetSustenance();
if( wops != 0 ){
wops->SendMessage( sendPacket );
}
else{
OutputDebug( "Sustenance WOPS connection is not establish.\n" );
}
}
}
void Database::InsertServerInfo( ServerInfo& info )
{
ServerInfo* newInfo = new ServerInfo;
memcpy( newInfo, &info, sizeof( ServerInfo ) );
newInfo->certifiedRTTAgent = 1;
newInfo->patchStatus = MSG_RTTG_PATCHRESULT_ANS::ERROR_NONE;
newInfo->launchProcessStatus = 0;
newInfo->userCountField = 0;
newInfo->userCountBattle = 0;
newInfo->preUserCountField = 0;
newInfo->preUserCountBattle = 0;
newInfo->userCountFieldOfPC = 0;
newInfo->userCountBattleOfPC = 0;
newInfo->preUserCountFieldOfPC = 0;
newInfo->preUserCountBattleOfPC = 0;
newInfo->HangameuserCountField = 0;
newInfo->HangameuserCountBattle = 0;
newInfo->preHangameUserCountField = 0;
newInfo->preHangameUserCountBattle = 0;
newInfo->HangameuserCountFieldOfPC = 0;
newInfo->HangameuserCountBattleOfPC = 0;
newInfo->preHangameUserCountFieldOfPC = 0;
newInfo->preHangameUserCountBattleOfPC = 0;
newInfo->PManguserCountField = 0;
newInfo->PManguserCountBattle = 0;
newInfo->prePMangUserCountField = 0;
newInfo->prePMangUserCountBattle = 0;
newInfo->PManguserCountFieldOfPC = 0;
newInfo->PManguserCountBattleOfPC = 0;
newInfo->prePMangUserCountFieldOfPC = 0;
newInfo->prePMangUserCountBattleOfPC = 0;
newInfo->bReceiveCurrentUser = true;
newInfo->userParentHistoryIDX = 0;
newInfo->agentParentHistoryIDX = 0;
m_listServerInfo.push_back( newInfo );
// RTTS는 따로 구분한다.
if( newInfo->ti_ServerType == (short)::GetPrivateProfileInt( "RTTServer", "RTTS_ServerType", 0, SERVERINFO_FILENAME )
&& newInfo->ti_ServerID == (short)::GetPrivateProfileInt( "RTTServer", "RTTS_ServerID", 0, SERVERINFO_FILENAME ) ){
m_svrInfoRTTS = newInfo;
}
}
void Database::InsertAdminInfo( AdminInfo& info )
{
AdminInfo* newInfo = new AdminInfo;
wcscpy( newInfo->UserID, info.UserID );
wcscpy( newInfo->IpAddr, info.IpAddr );
newInfo->LV = info.LV;
m_listAdminInfo.push_back( newInfo );
}
bool Database::FindServerID( wchar_t* innerIP, short *worldID, short *channelID, short *serverType, short *serverID )
{
ServerInfo* info = NULL;
// DB와의 연결상태를 체크한다.
if( m_flagReconnectDB == true )
return false;
for(ListServerInfo::iterator iter = m_listServerInfo.begin() ; iter != m_listServerInfo.end() ; iter++ )
{
info = *iter;
if( wcscmp( innerIP, info->vc_InnerIP ) == 0 )
{
*worldID = info->ti_WorldID;
*channelID = info->ti_ChannelID;
*serverType = info->ti_ServerType;
*serverID = info->ti_ServerID;
OutputDebug( "[Database::FindServerID] IP(%s) w(%d)c(%d)s(%d)i(%d).\n", innerIP, *worldID, *channelID, *serverType, *serverID);
return true;
}
}
*worldID = -1;
*channelID = -1;
*serverType = -1;
*serverID = -1;
OutputDebug( "[Database::FindServerID] IP(%s) w(%d)c(%d)s(%d)i(%d).\n", innerIP, *worldID, *channelID, *serverType, *serverID);
return false;
}
void Database::MakeServerList( ServerInfo* list[], DWORD bufferSize, DWORD* count )
{
*count = 0;
for(ListServerInfo::iterator iter = m_listServerInfo.begin() ; iter != m_listServerInfo.end() ; iter++ )
{
if( *count >= bufferSize )
return;
list[*count] = *iter;
( *count )++;
}
}
void Database::MakeServerListIn( wchar_t* innerIP, ServerInfo* list[], DWORD bufferSize, DWORD* count )
{
ServerInfo* info;
*count = 0;
for(ListServerInfo::iterator iter = m_listServerInfo.begin() ; iter != m_listServerInfo.end() ; iter++ )
{
if( *count >= bufferSize )
return;
info = *iter;
if( wcscmp( innerIP, info->vc_InnerIP ) == 0 )
{
list[*count] = info;
( *count )++;
}
}
}
void Database::MakeAdminList( AdminInfo* list[], DWORD bufferSize, DWORD* count )
{
*count = 0;
for(ListAdminInfo::iterator iter = m_listAdminInfo.begin() ; iter != m_listAdminInfo.end() ; iter++ )
{
if( *count >= bufferSize )
return;
list[*count] = *iter;
( *count )++;
}
}
void Database::AddAdmin( wchar_t* name, wchar_t* ip, DWORD attr )
{
AdminInfo* info = NULL;
AdminInfo newInfo = {0, };
for(ListAdminInfo::iterator iter = m_listAdminInfo.begin() ; iter != m_listAdminInfo.end() ; iter++ )
{
info = *iter;
if( wcscmp( info->UserID, name ) == 0 )
return;
}
// DB Procedure call
// try
// {
char mbcs[1024] = {0, };
char UserID[256] = {0, };
char IpAddr[256] = {0, };
::WideCharToMultiByte( CP_ACP, 0, name, -1, UserID, 256, 0, 0 );
::WideCharToMultiByte( CP_ACP, 0, ip, -1, IpAddr, 256, 0, 0 );
sprintf( mbcs, "INSERT INTO T_Manager VALUES('%s', %d, '%s', GetDate())", UserID, attr, IpAddr );
m_dbcWops.Query( 0, mbcs );
// }
// catch( eXtreme::ExceptionDBC& )
// {
// return;
// }
// Insert info to buffer
wcscpy( newInfo.UserID, name );
wcscpy( newInfo.IpAddr, ip );
newInfo.LV = ( short )attr;
InsertAdminInfo( newInfo );
}
void Database::RemoveAdmin( wchar_t* name )
{
AdminInfo* info = NULL;
for(ListAdminInfo::iterator iter = m_listAdminInfo.begin() ; iter != m_listAdminInfo.end() ; iter++ )
{
info = *iter;
if( wcscmp( info->UserID, name ) == 0 )
{
m_listAdminInfo.erase( iter );
delete info;
// DB Procedure call
// try
// {
char mbcs[1024] = {0, };
char UserID[256] = {0, };;
::WideCharToMultiByte( CP_ACP, 0, name, -1, UserID, 256, 0, 0 );
sprintf( mbcs, "DELETE FROM T_Manager WHERE UserID='%s'", UserID );
m_dbcWops.Query( 0, mbcs );
// }
// catch( eXtreme::ExceptionDBC& )
// {
// break;
// }
break;
}
}
}
void Database::CheckRTTAgentCertify( wchar_t* ip, bool certified )
{
ServerInfo* info = NULL;
for(ListServerInfo::iterator iter = m_listServerInfo.begin() ; iter != m_listServerInfo.end() ; iter++ )
{
info = *iter;
if( wcsncmp( info->vc_InnerIP, ip, 20 ) == 0 )
{
if( certified == true )
{
info->certifiedRTTAgent = 0;
/*
info->preUserCountBattle = 0;
info->preUserCountField = 0;
info->userCountBattle = 0;
info->userCountField = 0;
*/
}
else
{
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexWebRequest );
DWORD key = UID( info->ti_WorldID, info->ti_ChannelID, info->ti_ServerType, info->ti_ServerID);
m_MapWebRequest.erase(key); // 맵에서 에러정보 삭제
}
info->certifiedRTTAgent = 1;
/*
info->preUserCountBattle = 0;
info->preUserCountField = 0;
info->userCountBattle = 0;
info->userCountField = 0;
*/
}
}
}
}
void Database::ReloadWarningCanon()
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexWarningCanon );
TB_WarningCanon record;
char tmp[256] = {0, };
for(ListWarningCanon::iterator iter = m_listWarningCanon.begin() ; iter != m_listWarningCanon.end() ; iter++ )
{
WarningCanon* info = *iter;
sprintf( tmp, "{call USP_GetWarningCanonPerServer( %d, %d, %d, %d )}",
info->ti_WorldID, info->ti_ChannelID, info->ti_ServerType, info->ti_ServerID );
m_dbcWops.Query( &record, tmp );
if( record.IsEndRecord() == false )
memcpy( info, &record.record, sizeof( WarningCanon ) );
}
}
void Database::InsertResoureTable( short worldID, short channelID, short serverType, short serverID, wchar_t* serverIP )
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexSystemResource );
ResourceInfo* info = new ResourceInfo;
memset( info, 0, sizeof( ResourceInfo ) );
info->ti_WorldID = worldID;
info->ti_ChannelID = channelID;
info->ti_ServerType = serverType;
info->ti_ServerID = serverID;
char ip[16] = {0, };
::WideCharToMultiByte( CP_ACP, 0, serverIP, -1, ip, 16, 0, 0 );
strncpy(info->szServerIP, ip, 16);
info->szServerIP[15] = '\0';
info->b_HDDAlert = false;
m_listSystemResource.push_back( info );
}
void Database::UpdateBattleZoneInfo( short worldID, short channelID, short type, DWORD count )
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexBattleZone );
BattleZoneInfo* info = NULL;
for(ListBattleZoneInfo::iterator iter = m_listBattleZoneInfo.begin() ; iter != m_listBattleZoneInfo.end() ; iter++ )
{
info = *iter;
if( info->ti_worldID == worldID && info->ti_channelID == channelID && info->ti_zoneType == type )
{
info->i_roomCount = count;
break;
}
}
}
void Database::UpdateSupplyMoney( short worldID, short channelID, short /*serverType*/, short /*serverID*/, UINT64 get, UINT64 loss, UINT64 user, UINT64 wareHouseAvg, UINT64 wareHousePlus, UINT64 wareHouseMinus, USHORT usJackpotCnt, UINT64 ui64JackpotMoney, UINT64 ui64CirculateMoney)
{
SupplyMoney* info = NULL;
bool updated = false;
for(ListSupplyMoney::iterator iter = m_listSupplyMoney.begin() ; iter != m_listSupplyMoney.end() ; iter++ )
{
info = *iter;
if( info->ti_worldID == worldID && info->ti_channelID == channelID )
{
info->prevTotalGetMoney = info->totalGetMoney;
info->prevTotalLoseMoney = info->totalLoseMoney;
info->prevTotalUserMoney = info->totalUserMoney;
info->prevWareHouseAveMoney = info->wareHouseAveMoney;
info->prevWareHouseTotalPlusMoney = info->wareHouseTotalPlusMoney;
info->prevWareHouseTotalMinusMoney = info->wareHouseTotalMinusMoney;
//info->preJackpotCnt = info->jackpotCnt;
//info->preJackpotMoney = info->jackpotMoney;
info->totalGetMoney = get;
info->totalLoseMoney = loss;
info->totalUserMoney = user;
info->wareHouseAveMoney = wareHouseAvg;
info->wareHouseTotalPlusMoney = wareHousePlus;
info->wareHouseTotalMinusMoney = wareHouseMinus;
info->jackpotCnt = info->jackpotCnt + usJackpotCnt;
info->jackpotMoney += ui64JackpotMoney;
info->circulateMoney += ui64CirculateMoney;
updated = true;
break;
}
}
// 목록에 해당 world & channel 정보가 존재하지 않는다면
// 새로 할당하도록 한다.
if( updated == false )
{
info = new SupplyMoney;
info->ti_worldID = worldID;
info->ti_channelID = channelID;
info->totalGetMoney = get;
info->totalLoseMoney = loss;
info->totalUserMoney = user;
info->prevTotalGetMoney = get;
info->prevTotalLoseMoney = loss;
info->prevTotalUserMoney = user;
info->wareHouseAveMoney = wareHouseAvg;
info->wareHouseTotalPlusMoney = wareHousePlus;
info->wareHouseTotalMinusMoney = wareHouseMinus;
info->prevWareHouseAveMoney = wareHouseAvg;
info->prevWareHouseTotalPlusMoney = wareHousePlus;
info->prevWareHouseTotalMinusMoney = wareHouseMinus;
info->preJackpotCnt = usJackpotCnt;
info->preJackpotMoney = ui64JackpotMoney;
info->jackpotCnt = usJackpotCnt;
info->jackpotMoney = ui64JackpotMoney;
info->circulateMoney = ui64CirculateMoney;
m_listSupplyMoney.push_back( info );
}
}
void Database::UpdateGameStatistics( short worldID, short channelID, short /*serverType*/, short /*serverID*/, UINT64* ui64Statistics)
{
GameStatistics* info = NULL;
bool updated = false;
for(ListGameStatistics::iterator iter = m_listGameStatistics.begin() ; iter != m_listGameStatistics.end() ; iter++ )
{
info = *iter;
if( info->ti_worldID == worldID && info->ti_channelID == channelID )
{
// 통계 값 업데이트
for(int i=0;i<eSTATISTIC_MAX + 1;i++){
info->ui64Statistics[i] += ui64Statistics[i];
}
updated = true;
break;
}
}
// 목록에 해당 world & channel 정보가 존재하지 않는다면
// 새로 할당하도록 한다.
if( updated == false )
{
info = new GameStatistics;
info->ti_worldID = worldID;
info->ti_channelID = channelID;
for(int i=0;i<eSTATISTIC_MAX + 1;i++){
info->ui64Statistics[i] = ui64Statistics[i];
}
m_listGameStatistics.push_back( info );
}
//OutputDebug("[Database::UpdateGameStatistics](%d,%d)\n", worldID, channelID);
//OutputDebug("[Database::UpdateGameStatistics](%d,%d,%d,%d)\n", worldID, channelID, serverType, serverID);
}
void Database::UpdateSystemResource( ResourceInfo& info )
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexSystemResource );
ResourceInfo* systemInfo = NULL;
for(ListSystemResource::iterator iter = m_listSystemResource.begin() ; iter != m_listSystemResource.end() ; iter++ )
{
systemInfo = *iter;
if( systemInfo->ti_WorldID == info.ti_WorldID && systemInfo->ti_ChannelID == info.ti_ChannelID &&
systemInfo->ti_ServerType == info.ti_ServerType && systemInfo->ti_ServerID == info.ti_ServerID )
{
systemInfo->i_CpuMaxResource = info.i_CpuMaxResource;
systemInfo->i_CpuUseResource = info.i_CpuUseResource;
systemInfo->i_MemoryMaxResource = info.i_MemoryMaxResource;
systemInfo->i_MemoryUseResource = info.i_MemoryUseResource;
systemInfo->i_HDDMaxResource = info.i_HDDMaxResource;
systemInfo->i_HDDUseResource = info.i_HDDUseResource;
break;
}
}
}
void Database::UpdateCurrentUserCount( DWORD worldID, DWORD channelID, DWORD field, DWORD fieldOfPCRoom , DWORD battle, DWORD battleOfPCRoom, DWORD Hangamefield, DWORD HangamefieldOfPCRoom, DWORD Hangamebattle, DWORD HangamebattleOfPCRoom, DWORD PMangfield, DWORD PMangfieldOfPCRoom, DWORD PMangbattle, DWORD PMangbattleOfPCRoom)
{
ServerInfo* serverInfo = NULL;
for(ListServerInfo::iterator iter = m_listServerInfo.begin() ; iter != m_listServerInfo.end() ; iter++ )
{
serverInfo = *iter;
if( serverInfo->ti_WorldID == (short)worldID && serverInfo->ti_ChannelID == (short)channelID && serverInfo->ti_ServerID == 1)
{
if( serverInfo->ti_ServerType == 2 ) // Field
{
serverInfo->userCountField = field;
serverInfo->userCountFieldOfPC = fieldOfPCRoom;
serverInfo->HangameuserCountField = Hangamefield;
serverInfo->HangameuserCountFieldOfPC = HangamefieldOfPCRoom;
serverInfo->PManguserCountField = PMangfield;
serverInfo->PManguserCountFieldOfPC = PMangfieldOfPCRoom;
}
else if( serverInfo->ti_ServerType == 3 ) // Battle
{
serverInfo->userCountBattle = battle;
serverInfo->userCountBattleOfPC = battleOfPCRoom;
serverInfo->HangameuserCountBattle = Hangamebattle;
serverInfo->HangameuserCountBattleOfPC = HangamebattleOfPCRoom;
serverInfo->PManguserCountBattle = PMangbattle;
serverInfo->PManguserCountBattleOfPC = PMangbattleOfPCRoom;
}
else
{
continue;
}
// 동접 값을 받고 있음.
serverInfo->bReceiveCurrentUser = true;
/*
OutputDebug("[Database::UpdateCurrentUserCount]w(%d)c(%d)st(%d)si(%d) field(%5d/%5d, %5d/%5d, %5d/%5d) battle(%5d/%5d, %5d/%5d, %5d/%5d)\n"
,serverInfo->ti_WorldID
,serverInfo->ti_ChannelID
,serverInfo->ti_ServerType
,serverInfo->ti_ServerID
,field
,fieldOfPCRoom
,Hangamefield
,HangamefieldOfPCRoom
,PMangfield
,PMangfieldOfPCRoom
,battle
,battleOfPCRoom
,Hangamebattle
,HangamebattleOfPCRoom
,PMangbattle
,PMangbattleOfPCRoom
);
//*/
}
}
}
void Database::CheckSystemResource( ResourceInfo& info, int* warning, char* dateTime )
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexWarningCanon );
WarningCanon* warningDef = NULL;
// 요청된 리소스의 장애 기준값을 찾는다.
*warning = 0;
for(ListWarningCanon::iterator iter = m_listWarningCanon.begin() ; iter != m_listWarningCanon.end() ; iter++ )
{
warningDef = *iter;
if( warningDef->ti_WorldID == info.ti_WorldID && warningDef->ti_ChannelID == info.ti_ChannelID &&
warningDef->ti_ServerType == info.ti_ServerType && warningDef->ti_ServerID == info.ti_ServerID )
break;
warningDef = NULL;
}
if( NULL == warningDef ) // 기준값이 존재하지 않는다.
return;
if( info.i_CpuMaxResource == 0 && info.i_CpuUseResource == 0 &&
info.i_HDDMaxResource == 0 && info.i_HDDUseResource == 0 &&
info.i_MemoryMaxResource == 0 && info.i_MemoryUseResource == 0 )
return;
/*
2006.04.10
modify by guiun
리소스 장애처리 변경
장애는 한번 로그를 남긴고 정상 상태로 복구가 되면 다시 로그를 남긴다.
parentHistorIDX를 같이 남겨야 한다.
*/
// CPU 상한값
UINT cpuWarning = 0;
UINT memWarning = 0;
UINT hddWarning = 0;
char szBuffer[96] = {0, };
if( info.i_CpuUseResource >= warningDef->i_CpuUpperLimit ){
info.i_CpuUpperFrequency++;
if(info.i_CpuUpperFrequency>=warningDef->i_CpuUpperFrequency){ // 같은 경우에만 처리를 한다.
cpuWarning = CPU_UPPER_LIMIT;
}
}
else{
if(info.i_CpuUpperFrequency>=warningDef->i_CpuUpperFrequency){ // 정상 상태로 돌아온 경우
cpuWarning = CPU_NORMAL;
}
info.i_CpuUpperFrequency = 0;
}
if((cpuWarning==CPU_UPPER_LIMIT && info.i_CpuUpperFrequency==warningDef->i_CpuUpperFrequency) || cpuWarning==CPU_NORMAL){
sprintf(szBuffer, MSG_CPU_UPPER_LIMIT, info.i_CpuUseResource);
eXtreme::RecordSet rec;
// return parameter bind
if(cpuWarning==CPU_UPPER_LIMIT){ // 장애 보고 경우에만 return 값을 받는다.
rec.BindParameter(&info.i_CPU_ParentHistoryIDX, "", adInteger, adParamReturnValue, sizeof(int), "");
}
// input parameter bind
rec.BindParameter(NULL, "@WorldID" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_WorldID ));
rec.BindParameter(NULL, "@ChannelID" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_ChannelID ));
rec.BindParameter(NULL, "@ServerType" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_ServerType));
rec.BindParameter(NULL, "@ServerID" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_ServerID ));
rec.BindParameter(NULL, "@HitchDetailID" , adInteger, adParamInput, 4 , _bstr_t(cpuWarning ));
rec.BindParameter(NULL, "@nv_Message" , adVarChar, adParamInput, (long)strlen(szBuffer), _bstr_t(szBuffer ));
rec.BindParameter(NULL, "@dt_RegisterDate" , adVarChar, adParamInput, (long)strlen(dateTime), _bstr_t(dateTime ));
rec.BindParameter(NULL, "@ProcessName" , adVarChar, adParamInput, 1 , _bstr_t(" " ));
rec.BindParameter(NULL, "@AbsolutePath" , adVarChar, adParamInput, 1 , _bstr_t(" " ));
rec.BindParameter(NULL, "@ParentHistoryIDX" , adInteger, adParamInput, 4 , _bstr_t(info.i_CPU_ParentHistoryIDX));
// call storedProcedure
m_dbcWops.CallStoredProcedure(&rec, "USP_AddWarningHistoryForResource");
if(cpuWarning==CPU_NORMAL){ // 장애 복구 보고인 경우에는 ParentHistory를 0 으로 설정한다.
info.i_CPU_ParentHistoryIDX = 0;
}
else{
SendErrorNotifyNTF( info.ti_WorldID,
info.ti_ChannelID,
info.ti_ServerType,
info.ti_ServerID,
cpuWarning,
dateTime,
MSG_CPU_UPPER_LIMIT,
info.i_CpuUseResource );
}
}
// 메모리 상한값
DWORD percentageMem = (info.i_MemoryMaxResource > 0 ) ? info.i_MemoryUseResource * 100 / info.i_MemoryMaxResource : 0;
DWORD percentageHDD = (info.i_HDDMaxResource > 0 ) ? info.i_HDDUseResource * 100 / info.i_HDDMaxResource : 0;
memset(szBuffer, 0x00, 96);
if(percentageMem >= warningDef->i_MemoryUpperLimit){
info.i_MemoryUpperFrequency++;
if(info.i_MemoryUpperFrequency >= warningDef->i_MemoryUpperFrequency){
memWarning = MEMORY_UPPER_LIMIT;
}
}
else{
if(info.i_MemoryUpperFrequency>=warningDef->i_MemoryUpperFrequency){ // 정상 상태로 돌아온 경우
memWarning = MEM_NORMAL;
}
info.i_MemoryUpperFrequency = 0;
}
if((memWarning==MEMORY_UPPER_LIMIT && info.i_MemoryUpperFrequency==warningDef->i_MemoryUpperFrequency) || memWarning==MEM_NORMAL){
sprintf(szBuffer, MSG_MEMORY_UPPER_LIMIT, info.i_MemoryUseResource, info.i_MemoryMaxResource, percentageMem);
eXtreme::RecordSet rec;
// return parameter bind
if(memWarning==MEMORY_UPPER_LIMIT){ // 장애 보고 경우에만 return 값을 받는다.
rec.BindParameter(&info.i_MEM_ParentHistoryIDX, "", adInteger, adParamReturnValue, sizeof(int), "");
}
// input parameter bind
rec.BindParameter(NULL, "@WorldID" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_WorldID ));
rec.BindParameter(NULL, "@ChannelID" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_ChannelID ));
rec.BindParameter(NULL, "@ServerType" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_ServerType));
rec.BindParameter(NULL, "@ServerID" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_ServerID ));
rec.BindParameter(NULL, "@HitchDetailID" , adInteger, adParamInput, 4 , _bstr_t(memWarning ));
rec.BindParameter(NULL, "@nv_Message" , adVarChar, adParamInput, (long)strlen(szBuffer), _bstr_t(szBuffer ));
rec.BindParameter(NULL, "@dt_RegisterDate" , adVarChar, adParamInput, (long)strlen(dateTime), _bstr_t(dateTime ));
rec.BindParameter(NULL, "@ProcessName" , adVarChar, adParamInput, 1 , _bstr_t(" " ));
rec.BindParameter(NULL, "@AbsolutePath" , adVarChar, adParamInput, 1 , _bstr_t(" " ));
rec.BindParameter(NULL, "@ParentHistoryIDX" , adInteger, adParamInput, 4 , _bstr_t(info.i_MEM_ParentHistoryIDX));
// call storedProcedure
m_dbcWops.CallStoredProcedure(&rec, "USP_AddWarningHistoryForResource");
if(memWarning==MEM_NORMAL){ // 장애 복구 보고인 경우에는 ParentHistory를 0 으로 설정한다.
info.i_MEM_ParentHistoryIDX = 0;
}
else{
SendErrorNotifyNTF( info.ti_WorldID,
info.ti_ChannelID,
info.ti_ServerType,
info.ti_ServerID,
memWarning,
dateTime,
MSG_MEMORY_UPPER_LIMIT,
info.i_MemoryUseResource,
info.i_MemoryMaxResource,
percentageMem);
}
}
// HDD 용량
memset(szBuffer, 0x00, 96);
/*
if(info.b_HDDAlert==false){
if(info.i_HDDMaxResource > 0 && info.i_HDDMaxResource - info.i_HDDUseResource <= warningDef->i_HDDRemainder){ // 장애가 발생한 경우
hddWarning = HDD_LEAST_LIMIT;
info.b_HDDAlert = true;
}
}
else{ // 정상 상태가 된 경우
if((info.i_HDDMaxResource > 0 && info.i_HDDMaxResource - info.i_HDDUseResource <= warningDef->i_HDDRemainder )==false){
hddWarning = HDD_NORMAL;
info.b_HDDAlert = false;
}
}
*/
// 장애인 경우
if(info.i_HDDMaxResource > 0 && info.i_HDDMaxResource - info.i_HDDUseResource <= warningDef->i_HDDRemainder){ // 장애가 발생한 경우
hddWarning = HDD_LEAST_LIMIT;
}
// 장애 복구 알림이 필요한 상태 임을 확인한다.
if(info.b_HDDAlert==true){ // 정상 상태가 된 경우
if((info.i_HDDMaxResource > 0 && info.i_HDDMaxResource - info.i_HDDUseResource <= warningDef->i_HDDRemainder )==false){
hddWarning = HDD_NORMAL;
}
}
if((hddWarning==HDD_LEAST_LIMIT && info.b_HDDAlert==false) || (hddWarning==HDD_NORMAL && info.b_HDDAlert==true)){
sprintf(szBuffer, MSG_HDD_LEAST_LIMIT, info.i_HDDUseResource, info.i_HDDMaxResource, percentageHDD);
eXtreme::RecordSet rec;
// return parameter bind
if(hddWarning==HDD_LEAST_LIMIT){ // 장애 보고 경우에만 return 값을 받는다.
rec.BindParameter(&info.i_HDD_ParentHistoryIDX, "", adInteger, adParamReturnValue, sizeof(int), "");
}
// input parameter bind
rec.BindParameter(NULL, "@WorldID" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_WorldID ));
rec.BindParameter(NULL, "@ChannelID" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_ChannelID ));
rec.BindParameter(NULL, "@ServerType" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_ServerType));
rec.BindParameter(NULL, "@ServerID" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_ServerID ));
rec.BindParameter(NULL, "@HitchDetailID" , adInteger, adParamInput, 4 , _bstr_t(hddWarning ));
rec.BindParameter(NULL, "@nv_Message" , adVarChar, adParamInput, (long)strlen(szBuffer), _bstr_t(szBuffer ));
rec.BindParameter(NULL, "@dt_RegisterDate" , adVarChar, adParamInput, (long)strlen(dateTime), _bstr_t(dateTime ));
rec.BindParameter(NULL, "@ProcessName" , adVarChar, adParamInput, 1 , _bstr_t(" " ));
rec.BindParameter(NULL, "@AbsolutePath" , adVarChar, adParamInput, 1 , _bstr_t(" " ));
rec.BindParameter(NULL, "@ParentHistoryIDX" , adInteger, adParamInput, 4 , _bstr_t(info.i_HDD_ParentHistoryIDX));
// call storedProcedure
m_dbcWops.CallStoredProcedure(&rec, "USP_AddWarningHistoryForResource");
if(hddWarning==HDD_NORMAL){ // 장애 복구 보고인 경우에는 ParentHistory를 0 으로 설정한다.
info.i_HDD_ParentHistoryIDX = 0;
hddWarning = 0;
}
else{
SendErrorNotifyNTF( info.ti_WorldID,
info.ti_ChannelID,
info.ti_ServerType,
info.ti_ServerID,
hddWarning,
dateTime,
MSG_HDD_LEAST_LIMIT,
info.i_HDDUseResource,
info.i_HDDMaxResource,
percentageHDD);
}
info.b_HDDAlert = !info.b_HDDAlert;
}
// 장애인 경우 리턴 장애 코드를 해당 장애로 설정 해야 한다.
// 임의적인 우선순위로 장애 코드를 리턴 한다.
if(cpuWarning==CPU_UPPER_LIMIT){
*warning = cpuWarning;
}
else if(memWarning==MEMORY_UPPER_LIMIT){
*warning = memWarning;
}
else if(hddWarning==HDD_LEAST_LIMIT){
*warning = hddWarning;
}
else{
*warning = 0;
}
}
void Database::CheckCurrentUserCount(ServerInfo& info, int* warning, char* dateTime, bool bCheckAlive )
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexWarningCanon );
DWORD dwCurrentCount = 0;
DWORD dwPrevCount = 0;
*warning = 0;
/*
[2006.04.18] modify by guiun
*/
// 동접 값 변동에 대한 확인은 우선은 PC방과 개인 동접에 합을 가지고 처리를 한다.
if( info.ti_ServerType == 2 )
{
// 필드 동접
dwCurrentCount = info.userCountField + info.userCountFieldOfPC + info.HangameuserCountField + info.HangameuserCountFieldOfPC + info.PManguserCountField + info.PManguserCountFieldOfPC;
dwPrevCount = info.preUserCountField + info.preUserCountFieldOfPC + info.preHangameUserCountField + info.preHangameUserCountFieldOfPC + info.prePMangUserCountField + info.prePMangUserCountFieldOfPC;
}
else if( info.ti_ServerType == 3 )
{
// 배틀 동접
dwCurrentCount = info.userCountBattle + info.userCountBattleOfPC + info.HangameuserCountBattle + info.HangameuserCountBattleOfPC + info.PManguserCountBattle + info.PManguserCountBattleOfPC;
dwPrevCount = info.preUserCountBattle + info.preUserCountBattleOfPC + info.preHangameUserCountBattle + info.preHangameUserCountBattleOfPC + info.prePMangUserCountBattle + info.prePMangUserCountBattleOfPC;
}
else //이 경우는 존재 하지 않는다.
{
return;
}
// prevCount == 0 이면 서비스를 시작한 순간이므로, 이 경우 오류로그를 판단하지 않는다.
if(dwPrevCount==0 && info.userParentHistoryIDX==0)
{
// OutputDebug("[Database::CheckCurrentUserCount] Service initialize, dwPrevCount==0, return\n");
return;
}
if( info.ti_ServerType == 2 )
{
/*
OutputDebug("[Database::CheckCurrentUserCount]w(%d)c(%d)st(%d)si(%d) field_(%5d/%5d, %5d/%5d, %5d/%5d) pre_field_(%5d/%5d, %5d/%5d, %5d/%5d) (%7d/%7d)\n"
, info.ti_WorldID
, info.ti_ChannelID
, info.ti_ServerType
, info.ti_ServerID
, info.userCountField
, info.userCountFieldOfPC
, info.HangameuserCountField
, info.HangameuserCountFieldOfPC
, info.PManguserCountField
, info.PManguserCountFieldOfPC
, info.preUserCountField
, info.preUserCountFieldOfPC
, info.preHangameUserCountField
, info.preHangameUserCountFieldOfPC
, info.prePMangUserCountField
, info.prePMangUserCountFieldOfPC
, dwCurrentCount
, dwPrevCount);
//*/
}
else if( info.ti_ServerType == 3 )
{
/*
OutputDebug("[Database::CheckCurrentUserCount]w(%d)c(%d)st(%d)si(%d) battle(%5d/%5d, %5d/%5d, %5d/%5d) pre_battle(%5d/%5d, %5d/%5d, %5d/%5d) (%7d/%7d)\n"
, info.ti_WorldID
, info.ti_ChannelID
, info.ti_ServerType
, info.ti_ServerID
, info.userCountBattle
, info.userCountBattleOfPC
, info.HangameuserCountBattle
, info.HangameuserCountBattleOfPC
, info.PManguserCountField
, info.PManguserCountFieldOfPC
, info.preUserCountBattle
, info.preUserCountBattleOfPC
, info.preHangameUserCountBattle
, info.preHangameUserCountBattleOfPC
, info.prePMangUserCountField
, info.prePMangUserCountFieldOfPC
, dwCurrentCount
, dwPrevCount);
//*/
}
///////////////////////////////////////////////
// 요청된 리소스의 장애 기준값을 찾는다.
WarningCanon* warningDef = NULL;
for(ListWarningCanon::iterator iter = m_listWarningCanon.begin() ; iter != m_listWarningCanon.end() ; iter++ )
{
warningDef = *iter;
if( warningDef->ti_WorldID == info.ti_WorldID ) break;
warningDef = NULL;
}
if( NULL == warningDef)
{
return; // 기준값이 존재하지 않는다.
}
char szMsgFormat[32] = {0, };
DWORD dwWarning = 0;
// 마스터 동접값 체크와 동접 체크가 주기가 다르므로 만약 에러시에는 다음과 같이 인위적으로 마스터 장애를 체크 하게 한다.
if(bCheckAlive==false && info.userParentHistoryIDX>0)
{
bCheckAlive = true;
}
/*
[2006.04.18] add by guiun
Master 서버에서 동접 값을 전송 하고 있는지 확인을 한다.
*/
DWORD dwParentHistoryIDX = 0;
if(bCheckAlive==true)
{
if(info.bReceiveCurrentUser==false) // 동접 값을 받지 못하고 있는 경우
{
if(info.userParentHistoryIDX==0) // userParentHistoryIDX가 0인 경우는 아직 해당 에러가 발생되지 않았다는 것이다.
{
dwWarning = MASTER_SERVER_ERROR;
strncpy(szMsgFormat, " ", 1);
// 동접 값을 받고 있지 못하므로 값을 초기화 한다.
info.userCountBattle = 0;
info.userCountField = 0;
info.userCountBattleOfPC = 0;
info.userCountFieldOfPC = 0;
info.preUserCountBattle = 0;
info.preUserCountField = 0;
info.preUserCountBattleOfPC = 0;
info.preUserCountFieldOfPC = 0;
info.HangameuserCountBattle = 0;
info.HangameuserCountField = 0;
info.HangameuserCountBattleOfPC = 0;
info.HangameuserCountFieldOfPC = 0;
info.preHangameUserCountBattle = 0;
info.preHangameUserCountField = 0;
info.preHangameUserCountBattleOfPC = 0;
info.preHangameUserCountFieldOfPC = 0;
info.PManguserCountBattle = 0;
info.PManguserCountField = 0;
info.PManguserCountBattleOfPC = 0;
info.PManguserCountFieldOfPC = 0;
info.prePMangUserCountBattle = 0;
info.prePMangUserCountField = 0;
info.prePMangUserCountBattleOfPC = 0;
info.prePMangUserCountFieldOfPC = 0;
OutputDebug("[Database::CheckCurrentUserCount]w(%d)c(%d)st(%d)si(%d) 동접 초기화\n", info.ti_WorldID, info.ti_ChannelID, info.ti_ServerType, info.ti_ServerID);
}
}
else
{
if(info.userParentHistoryIDX!=0) // 장애에서 복구 상태가 된 경우이다.
{
dwWarning = MASTER_SERVER_SUCCESS;
strncpy(szMsgFormat, " ", 1);
dwParentHistoryIDX = info.userParentHistoryIDX;
info.userParentHistoryIDX = 0;
}
info.bReceiveCurrentUser = false; // UpdateCurrentUserCount에서 동접 값을 받으면 이 변수를 true로 바꾸어 줄것이다.
}
}
if(dwWarning==0) // 동접 값 체크를 한 경우에 아무런 이상이 없는 경우 폭증/폭감에 대한 확인을 한다.
{
/*
2006.04.15
modify by guiun
*/
if(dwPrevCount>dwCurrentCount) // 폭감 체크
{
if((dwPrevCount - dwCurrentCount ) > (warningDef->i_ConnectCountUnderGap))
{
dwWarning = USERCOUNT_GAPLOWER;
sprintf(szMsgFormat, MSG_USERCOUNT_GAPLOWER, dwPrevCount, dwCurrentCount);
}
}
else if(dwPrevCount<dwCurrentCount) // 폭증 체크
{
if((dwCurrentCount - dwPrevCount) > (warningDef->i_ConnectCountOverGap))
{
dwWarning = USERCOUNT_GAPOVER;
sprintf(szMsgFormat, MSG_USERCOUNT_GAPOVER, dwPrevCount, dwCurrentCount);
}
}
}
if(dwWarning!=0) // 장애가 발생하였으므로 장애 로그를 남긴다.
{
eXtreme::RecordSet rec;
rec.m_callbackError = Database::CallbackErrorRecordSet;
if(dwWarning==MASTER_SERVER_ERROR) // return parameter bind MasterServer 장애 발생시에만 HistoryIDX를 받는다.
{
rec.BindParameter(&info.userParentHistoryIDX, "", adInteger, adParamReturnValue, sizeof(int), "");
}
// input parameter bind
rec.BindParameter(NULL, "@WorldID" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_WorldID ));
rec.BindParameter(NULL, "@ChannelID" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_ChannelID ));
rec.BindParameter(NULL, "@ServerType" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_ServerType));
rec.BindParameter(NULL, "@ServerID" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_ServerID ));
rec.BindParameter(NULL, "@HitchDetailID" , adInteger, adParamInput, 4 , _bstr_t(dwWarning ));
rec.BindParameter(NULL, "@nv_Message" , adVarChar, adParamInput, (long)strlen(szMsgFormat) , _bstr_t(szMsgFormat ));
rec.BindParameter(NULL, "@dt_RegisterDate" , adVarChar, adParamInput, (long)strlen(dateTime) , _bstr_t(dateTime ));
rec.BindParameter(NULL, "@ParentHistoryIDX" , adInteger, adParamInput, 4 , _bstr_t(dwParentHistoryIDX));
// call storedProcedure
m_dbcWops.CallStoredProcedure(&rec, "USP_AddWarningHistoryForConnectCount");
SendErrorNotifyNTF( info.ti_WorldID,
info.ti_ChannelID,
info.ti_ServerType,
info.ti_ServerID,
dwWarning,
dateTime,
szMsgFormat);
}
else // 장애 상태가 계속 되고 있으면 장애 코드만 리턴을 해준다.
{
if(bCheckAlive==true && info.userParentHistoryIDX>0)
{
dwWarning = MASTER_SERVER_ERROR;
}
}
if(dwWarning!=MASTER_SERVER_SUCCESS)
{
*warning = dwWarning;
}
}
void Database::CheckProcess( ServerProcess& info, int* warning, char* dateTime )
{
char filename[20] = {0, };
char path[100] = {0, };
//DWORD dwAlert = 0;
*warning = 0;
::WideCharToMultiByte( CP_ACP, 0, info.vc_AbsolutePath, -1, path, 100, 0, 0 );
::WideCharToMultiByte( CP_ACP, 0, info.vc_ProcessName, -1, filename, 100, 0, 0 );
/*
2006.04.15
modify by guiun
복구 기록시 parentHistoryIdx를 입력 하기 위하여 장애 기록시 historyIdx를 프로시져 결과로 받는다.
*/
*warning = 0;
if(info.dw_alert==1){ // 장애 기록
*warning = PROCESS_SHUTDOWN;
info.dw_alert = 2;
}
else if(info.dw_alert==3){ // 복구 기록
*warning = PROCESS_STARTUP;
}
if(*warning!=0){
char szBuffer[96] = {0, };
sprintf(szBuffer, MSG_PROCESS_SHUTDOWN, filename);
eXtreme::RecordSet rec;
rec.m_callbackError = Database::CallbackErrorRecordSet;
// return parameter bind
//if(*warning==PROCESS_SHUTDOWN){ // 장애 보고 경우에만 return 값을 받는다.
//}
rec.BindParameter(&info.i_ParentHistoryIDX, "", adInteger, adParamReturnValue, sizeof(int), "");
// input parameter bind
rec.BindParameter(NULL, "@WorldID" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_WorldID ));
rec.BindParameter(NULL, "@ChannelID" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_ChannelID ));
rec.BindParameter(NULL, "@ServerType" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_ServerType));
rec.BindParameter(NULL, "@ServerID" , adTinyInt, adParamInput, 1 , _bstr_t(info.ti_ServerID ));
rec.BindParameter(NULL, "@HitchDetailID" , adInteger, adParamInput, 4 , _bstr_t(*warning ));
rec.BindParameter(NULL, "@nv_Message" , adVarChar, adParamInput, (long)strlen(szBuffer), _bstr_t(szBuffer ));
rec.BindParameter(NULL, "@dt_RegisterDate" , adVarChar, adParamInput, (long)strlen(dateTime), _bstr_t(dateTime ));
rec.BindParameter(NULL, "@ProcessName" , adVarChar, adParamInput, 100 , _bstr_t(filename ));
rec.BindParameter(NULL, "@AbsolutePath" , adVarChar, adParamInput, 100 , _bstr_t(path ));
rec.BindParameter(NULL, "@ParentHistoryIDX" , adInteger, adParamInput, 4 , _bstr_t(info.i_ParentHistoryIDX));
// call storedProcedure
m_dbcWops.CallStoredProcedure(&rec, "USP_AddWarningHistoryForResource");
SendErrorNotifyNTF( info.ti_WorldID,
info.ti_ChannelID,
info.ti_ServerType,
info.ti_ServerID,
*warning,
dateTime,
MSG_PROCESS_SHUTDOWN,
filename );
if(*warning==PROCESS_STARTUP){ // 장애 복구 보고인 경우에는 ParentHistory를 0 으로 설정한다.
info.i_ParentHistoryIDX = 0;
info.dw_alert = 0;
}
// DB에 기록되었음을 체크한다.
MonitorProcess::Instance()->SetProcessAlert( info.ti_WorldID, info.ti_ChannelID, info.ti_ServerType, info.ti_ServerID, info.vc_InnerIP,
info.vc_ProcessName, info.vc_AbsolutePath, info.dw_alert, info.i_ParentHistoryIDX);
//MonitorProcess::Instance()->SetProcessAlert( info.ti_WorldID, info.ti_ChannelID, info.ti_ServerType, info.ti_ServerID,,
// info.vc_ProcessName, info.vc_AbsolutePath, info.dw_alert, info.i_ParentHistoryIDX);
}
}
void Database::CheckSupplyMoney( SupplyMoney& info, int* warning, char* dateTime )
{
char queryStr[256] = {0, };
char message[256] = {0, };
*warning = 0;
// 장애 판단
// 얻은 돈의 증감 % = a, 평균보유금액의 증감 % = b
// abs( a - b ) > m_stdMoneyGap 이면 장애처리.
/*
UINT64 percentageGetMoney = (info.prevTotalGetMoney!=0)
? ( info.totalGetMoney - info.prevTotalGetMoney ) * 100 / info.prevTotalGetMoney
: 0;
*/
/*
int percentageUserMoney = (info.prevTotalUserMoney!=0)
? (int)((info.totalUserMoney - info.prevTotalUserMoney) * 100 / info.prevTotalUserMoney)
: 0;
int percentageGetMoney = (info.prevTotalGetMoney!=0)
? (int)((__int64)(info.totalGetMoney - info.prevTotalGetMoney) * 100 / info.prevTotalGetMoney)
: 0;
int percentageLoseMoney = (info.prevTotalLoseMoney!=0)
? (int)((info.totalLoseMoney - info.prevTotalLoseMoney) * 100 / info.prevTotalLoseMoney)
: 0;
*/
/*
int percentageGetMoney = 0;
__int64 temp1 = (info.totalGetMoney - info.prevTotalGetMoney);
__int64 tmep2 = temp1 * 100;
__int64 temp3 = ( tmep2 / (__int64)info.prevTotalGetMoney);
percentageGetMoney = (int)temp3;
*/
int percentageGetMoney = (info.prevTotalGetMoney!=0)
? (int)((__int64)(info.totalGetMoney - info.prevTotalGetMoney) * 100 / (__int64)info.prevTotalGetMoney)
: 0;
// 얻은 통화 장애 발생 조건
if(abs(percentageGetMoney) >= (int)m_stdMoneyGap){
// 장애처리
sprintf( message, MSG_SUPPLYMONEY_ERROR, info.prevTotalGetMoney, info.totalGetMoney, percentageGetMoney);
*warning = SUPPLYMONEY_ERROR;
sprintf( queryStr, "{call USP_AddWarningHistoryForMoney(%d, %d, %d, '%s', '%s')}",
info.ti_worldID, info.ti_channelID, SUPPLYMONEY_ERROR, message, dateTime );
m_dbcWops.Query( 0, queryStr );
SendErrorNotifyNTF( info.ti_worldID,
info.ti_channelID,
0,
0,
*warning,
dateTime,
message );
}
/*
if(info.prevTotalGetMoney!=0){
if(info.totalGetMoney > info.prevTotalGetMoney){
percentageGetMoney = (info.totalGetMoney - info.prevTotalGetMoney) * 100 / info.prevTotalGetMoney;
}
else{
percentageGetMoney = (info.prevTotalGetMoney - info.totalGetMoney) * 100 / info.prevTotalGetMoney;
}
}
if(info.prevTotalUserMoney!=0){
if(info.totalUserMoney > info.prevTotalUserMoney){
percentageUserMoney = (info.totalUserMoney - info.prevTotalUserMoney) * 100 / info.prevTotalUserMoney;
}
else{
percentageUserMoney = (info.prevTotalUserMoney - info.totalUserMoney) * 100 / info.prevTotalUserMoney;
}
}
if( _abs64( ( percentageGetMoney - percentageUserMoney ) ) >= ( int )m_stdMoneyGap )
{
// 장애처리
sprintf( message, MSG_SUPPLYMONEY_ERROR, percentageGetMoney, percentageUserMoney );
*warning = SUPPLYMONEY_ERROR;
sprintf( queryStr, "{call USP_AddWarningHistoryForMoney(%d, %d, %d, '%s', '%s')}",
info.ti_worldID, info.ti_channelID, SUPPLYMONEY_ERROR, message, dateTime );
m_dbcWops.Query( 0, queryStr );
SendErrorNotifyNTF( info.ti_worldID,
info.ti_channelID,
0,
0,
*warning,
dateTime,
MSG_SUPPLYMONEY_ERROR,
percentageGetMoney,
percentageUserMoney );
}
*/
}
void Database::ClearResourceInfo()
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexSystemResource );
ResourceInfo* resourceInfo = NULL;
for(ListSystemResource::iterator iter = m_listSystemResource.begin() ; iter != m_listSystemResource.end() ; iter++ )
{
resourceInfo = *iter;
resourceInfo->i_CpuMaxResource = 0;
resourceInfo->i_CpuUseResource = 0;
resourceInfo->i_MemoryMaxResource = 0;
resourceInfo->i_HDDUseResource = 0;
resourceInfo->i_HDDMaxResource = 0;
resourceInfo->i_HDDUseResource = 0;
}
}
void Database::SP_CURRENT_RESOURCE_INSERT( char* dateTime )
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexSystemResource );
ResourceInfo* resourceInfo = NULL;
int warningCode = 0;
char temp[256] = {0, };
std::string queryStr;
queryStr = std::string( "SET XACT_ABORT On;" );
queryStr += std::string( "Begin Tran;" );
queryStr += std::string( "Delete From TB_CurrentTimeResourceLog;" );
for(ListSystemResource::iterator iter = m_listSystemResource.begin() ; iter != m_listSystemResource.end() ; iter++ )
{
// bool hasError = false;
int hasError = 0; // 0 : 에러없음, 1 : Request 에러, 2 : 프로세스 에러, 3 : 리소스 에러
resourceInfo = *iter;
// Request 에러가 있다면 우선순위상 가장 높으므로 이를 기록한다
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexWebRequest );
DWORD key = UID( resourceInfo->ti_WorldID, resourceInfo->ti_ChannelID, resourceInfo->ti_ServerType, resourceInfo->ti_ServerID ); // 서버 키를 구한다
MapWebRequest::iterator iter = m_MapWebRequest.find(key);
if( iter != m_MapWebRequest.end() )
{
hasError = 1; // Request 에러
resourceInfo->i_WarningKey = iter->second;
}
}
{
// Process 정보
ServerProcess processList[20] = {0, };
int size = 0;
MonitorProcess::Instance()->GetList( resourceInfo->ti_WorldID, resourceInfo->ti_ChannelID,
resourceInfo->ti_ServerType, resourceInfo->ti_ServerID, resourceInfo->szServerIP, processList, 20, &size );
for(int i = 0 ; i < size ; i++ )
{
// 접속 되어 있는 RTTAgent에 대해서만 프로세스 감시를 한다.
//if(ManagerClient::Instance()->FindClient( resourceInfo->ti_WorldID,
// resourceInfo->ti_ChannelID,
// resourceInfo->ti_ServerType,
// resourceInfo->ti_ServerID ) != NULL)
// 접속 되어 있는 RTTAgent에 대해서만 프로세스 감시를 한다.
if(ManagerClient::Instance()->FindClient( resourceInfo->szServerIP ) != NULL)
{
// 이 함수에서는 프로세스의 상태를 계속 기록한다.
CheckProcess( processList[i], &warningCode, dateTime );
if( processList[i].dwStatus == 0 )
{
if( 0 == hasError ) // Request 에러가 없으면 프로세스 에러를 기록
{
resourceInfo->i_WarningKey = PROCESS_SHUTDOWN;
hasError = 2; // 프로세스 에러
}
//resourceInfo->i_WarningKey = PROCESS_SHUTDOWN;
// hasError = true;
// Process 에러는 1개만 보고되어야 하므로 1개 기록후 루프를 종료한다.
break;
}
/*
else if( processList[i].dwStatus == 1 )
{
// 프로세스가 살아있는 상태는 기록하지 않는다.
}
*/
}
}
}
// 리소스의 상태를 기록한다
CheckSystemResource( *resourceInfo, &warningCode, dateTime );
// 실시간 에러보고는 ServerKey당 1개만 남아야 하기때문에,
// Process에러가 보고되면 우선순위상 리소스 에러는 보고하지 않는다.
if( 0 == hasError )
{
if(warningCode==CPU_UPPER_LIMIT || warningCode==MEMORY_UPPER_LIMIT || warningCode==HDD_LEAST_LIMIT)
{
resourceInfo->i_WarningKey = warningCode; // 장애인 경우
hasError = 3; // 리소스 에러
}
}
if( 0 == hasError )
{
resourceInfo->i_WarningKey = 0;
}
/*
//if(hasError==false){
// if(warningCode==CPU_UPPER_LIMIT || warningCode==MEMORY_UPPER_LIMIT || warningCode==HDD_LEAST_LIMIT){
// resourceInfo->i_WarningKey = warningCode; // 장애인 경우
// hasError=true;
// }
//}
//if(hasError==false) resourceInfo->i_WarningKey = 0;
*/
sprintf( temp, "EXEC USP_CURRENT_RESOURCE_INSERT '%s', %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d;",
dateTime,
resourceInfo->ti_WorldID,
resourceInfo->ti_ChannelID,
resourceInfo->ti_ServerType,
resourceInfo->ti_ServerID,
resourceInfo->i_CpuUseResource,
resourceInfo->i_CpuMaxResource,
resourceInfo->i_MemoryUseResource,
resourceInfo->i_MemoryMaxResource,
resourceInfo->i_HDDUseResource,
resourceInfo->i_HDDMaxResource,
resourceInfo->i_WarningKey );
queryStr += std::string( temp );
}
queryStr += std::string( "IF @@Error <> 0 RollBack Tran Else Commit Tran;" );
queryStr += std::string( "SET XACT_ABORT Off;" );
m_dbcWops.Query( 0, queryStr.data() );
}
void Database::SP_CURRENT_USER_INSERT( char* dateTime, bool bCheckAlive )
{
ServerInfo* serverInfo = NULL;
char temp[256] = {0, };
std::string queryStr;
int warningCode = 0;
queryStr = std::string( "SET XACT_ABORT On;" );
queryStr += std::string( "Begin Tran;" );
queryStr += std::string( "Delete From TB_CurrentTimeConnectLog;" );
queryStr += std::string( "Declare @CurrentTime DateTime;" );
queryStr += std::string( "Set @CurrentTime = getdate();" );
DWORD dwConnectCountOfPersonal = 0; // 기존 썬 유저 개인 동접
DWORD dwConnectCountOfPC = 0; // 기존 썬 유저 PC방 동접
DWORD dwHangameConnectCountOfPersonal = 0; // 한게임계정 개인 동접
DWORD dwHangameConnectCountOfPC = 0; // 한게임계정 PC방 동접
DWORD dwPMangConnectCountOfPersonal = 0; // 피망계정 개인 동접
DWORD dwPMangConnectCountOfPC = 0; // 피망계정 PC방 동접
for(ListServerInfo::iterator iter = m_listServerInfo.begin() ; iter != m_listServerInfo.end() ; iter++ )
{
serverInfo = *iter;
// Field 및 Battle 서버인 경우만 동접 값을 처리한다.
// ServerID가 1인 서버만 동접 값을 받고 있다.
if(serverInfo->ti_ServerType==2 || (serverInfo->ti_ServerType==3 && serverInfo->ti_ServerID==1))
{
// 동접 값에 대한 확인을 한다.
CheckCurrentUserCount(*serverInfo, &warningCode, dateTime, bCheckAlive);
if(serverInfo->ti_ServerType==2)
{
// 필드 동접
dwConnectCountOfPersonal = serverInfo->userCountField; // 기존 썬 유저 개인 동접
dwConnectCountOfPC = serverInfo->userCountFieldOfPC; // 기존 썬 유저 PC방 동접
dwHangameConnectCountOfPersonal = serverInfo->HangameuserCountField; // 한게임계정 개인 동접
dwHangameConnectCountOfPC = serverInfo->HangameuserCountFieldOfPC; // 한게임계정 PC방 동접
dwPMangConnectCountOfPersonal = serverInfo->PManguserCountField; // 피망계정 개인 동접
dwPMangConnectCountOfPC = serverInfo->PManguserCountFieldOfPC; // 피망계정 PC방 동접
}
else
{
// 배틀존 동접
dwConnectCountOfPersonal = serverInfo->userCountBattle; // 기존 썬 유저 개인 동접
dwConnectCountOfPC = serverInfo->userCountBattleOfPC; // 기존 썬 유저 PC방 동접
dwHangameConnectCountOfPersonal = serverInfo->HangameuserCountBattle; // 한게임계정 개인 동접
dwHangameConnectCountOfPC = serverInfo->HangameuserCountBattleOfPC; // 한게임계정 PC방 동접
dwPMangConnectCountOfPersonal = serverInfo->PManguserCountBattle; // 피망계정 개인 동접
dwPMangConnectCountOfPC = serverInfo->PManguserCountBattleOfPC; // 피망계정 PC방 동접
}
memset(temp, 0x00, 256);
// 한게임, 피망 계정으로 접속한 유저의 동접정보 추가 Insert
#ifdef _090901_CHANNELLING_CONNECT_USER_
sprintf( temp, "EXEC USP_CURRENT_USER_INSERT '%s', %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d;",
dateTime,
serverInfo->ti_WorldID,
serverInfo->ti_ChannelID,
serverInfo->ti_ServerType,
serverInfo->ti_ServerID,
dwConnectCountOfPersonal, // 기존 썬 유저 개인 동접
dwConnectCountOfPC, // 기존 썬 유저 PC방 동접
dwHangameConnectCountOfPersonal, // 한게임계정 개인 동접
dwHangameConnectCountOfPC, // 한게임계정 PC방 동접
dwPMangConnectCountOfPersonal, // 피망계정 개인 동접
dwPMangConnectCountOfPC, // 피망계정 PC방 동접
warningCode );
#else // 기존 유저의 동접정보 Insert
sprintf( temp, "EXEC USP_CURRENT_USER_INSERT '%s', %d, %d, %d, %d, %d, %d, %d;",
dateTime,
serverInfo->ti_WorldID,
serverInfo->ti_ChannelID,
serverInfo->ti_ServerType,
serverInfo->ti_ServerID,
dwConnectCountOfPersonal, // 기존 썬 유저 개인 동접
dwConnectCountOfPC, // 기존 썬 유저 PC방 동접
warningCode );
#endif
queryStr += std::string( temp );
serverInfo->preUserCountField = serverInfo->userCountField;
serverInfo->preUserCountFieldOfPC = serverInfo->userCountFieldOfPC;
serverInfo->preUserCountBattle = serverInfo->userCountBattle;
serverInfo->preUserCountBattleOfPC = serverInfo->userCountBattleOfPC;
serverInfo->preHangameUserCountField = serverInfo->HangameuserCountField;
serverInfo->preHangameUserCountFieldOfPC = serverInfo->HangameuserCountFieldOfPC;
serverInfo->preHangameUserCountBattle = serverInfo->HangameuserCountBattle;
serverInfo->preHangameUserCountBattleOfPC = serverInfo->HangameuserCountBattleOfPC;
serverInfo->prePMangUserCountField = serverInfo->PManguserCountField;
serverInfo->prePMangUserCountFieldOfPC = serverInfo->PManguserCountFieldOfPC;
serverInfo->prePMangUserCountBattle = serverInfo->PManguserCountBattle;
serverInfo->prePMangUserCountBattleOfPC = serverInfo->PManguserCountBattleOfPC;
/*
OutputDebug("[Database::SP_CURRENT_USER_INSERT]w(%d)c(%d)st(%d)si(%d) (%d/%d, %d/%d, %d/%d) field info(%d/%d, %d/%d, %d/%d), battleinfo(%d/%d, %d/%d, %d/%d)\n"
, serverInfo->ti_WorldID
, serverInfo->ti_ChannelID
, serverInfo->ti_ServerType
, serverInfo->ti_ServerID
, dwConnectCountOfPersonal
, dwConnectCountOfPC
, dwHangameConnectCountOfPersonal
, dwHangameConnectCountOfPC
, dwPMangConnectCountOfPersonal
, dwPMangConnectCountOfPC
, serverInfo->userCountField
, serverInfo->userCountFieldOfPC
, serverInfo->HangameuserCountField
, serverInfo->HangameuserCountFieldOfPC
, serverInfo->PManguserCountField
, serverInfo->PManguserCountFieldOfPC
, serverInfo->userCountBattle
, serverInfo->userCountBattleOfPC
, serverInfo->HangameuserCountBattle
, serverInfo->HangameuserCountBattleOfPC
, serverInfo->PManguserCountBattle
, serverInfo->PManguserCountBattleOfPC
);
//*/
}
}
queryStr += std::string( "IF @@Error <> 0 RollBack Tran Else Commit Tran;" );
queryStr += std::string( "SET XACT_ABORT Off;" );
m_dbcWops.Query( 0, queryStr.data() );
}
void Database::SP_CURRENT_BattleZone_INSERT( char* dateTime )
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexBattleZone );
BattleZoneInfo* info = NULL;
char temp[256] = {0, };
std::string queryStr;
queryStr = std::string( "SET XACT_ABORT On;" );
queryStr += std::string( "Begin Tran;" );
queryStr += std::string( "Delete From TB_CurrentTimeBattleZoneLog;" );
for(ListBattleZoneInfo::iterator iter = m_listBattleZoneInfo.begin() ; iter != m_listBattleZoneInfo.end() ; iter++ )
{
info = *iter;
sprintf( temp, "EXEC USP_CURRENT_BattleZone_INSERT '%s', %d, %d, %d, %d;",
dateTime, info->ti_worldID, info->ti_channelID, info->ti_zoneType, info->i_roomCount );
queryStr += std::string( temp );
}
queryStr += std::string( "IF @@Error <> 0 RollBack Tran Else Commit Tran;" );
queryStr += std::string( "SET XACT_ABORT Off;" );
m_dbcWops.Query( 0, queryStr.data() );
}
void Database::SP_CURRENT_Money_INSERT( char* dateTime )
{
SupplyMoney* info = NULL;
int warningCode = 0;
char temp[256] = {0, };
char jackpotQuery[256] = {0, };
std::string queryStr;
if( m_listSupplyMoney.size() == 0 )
return;
queryStr = std::string( "SET XACT_ABORT On;" );
queryStr += std::string( "Begin Tran;" );
//queryStr += std::string( "Delete From TB_CurrentTimeMoneyLog;" );
for(ListSupplyMoney::iterator iter = m_listSupplyMoney.begin() ; iter != m_listSupplyMoney.end() ; iter++ )
{
info = *iter;
CheckSupplyMoney( *info, &warningCode, dateTime );
sprintf( temp, "EXEC USP_CURRENT_Money_INSERT '%s', %d, %d, %I64d, %I64d, %I64d, %I64d, %I64d, %I64d, %d, %I64d;",
dateTime,
info->ti_worldID,
info->ti_channelID,
info->totalGetMoney,
info->totalLoseMoney,
info->totalUserMoney,
info->wareHouseTotalPlusMoney,
info->wareHouseTotalMinusMoney,
info->wareHouseAveMoney,
warningCode,
info->circulateMoney);
queryStr += std::string( temp );
// 상거래 금액 초기화
info->circulateMoney = 0;
/// jackpot 관련 처리 ///////////////////////
//USHORT usJackpotCnt = info->jackpotCnt;
//UINT64 ui64JackpotMoney = info->jackpotMoney;
if(info->jackpotCnt>0){
memset(jackpotQuery, 0x00, 256);
sprintf(jackpotQuery, "EXEC USP_AddJackPotLog '%s', %d, %d, %I64d, %d;",
dateTime,
info->ti_worldID,
info->ti_channelID,
info->jackpotMoney,
info->jackpotCnt);
info->preJackpotCnt = info->jackpotCnt;
info->preJackpotMoney = info->jackpotMoney;
info->jackpotCnt = 0;
info->jackpotMoney = 0;
queryStr += std::string( jackpotQuery );
}
}
queryStr += std::string( "IF @@Error <> 0 RollBack Tran Else Commit Tran;" );
queryStr += std::string( "SET XACT_ABORT Off;" );
m_dbcWops.Query( 0, queryStr.data() );
}
void Database::SP_CURRENT_GameStatistics_INSERT( char* dateTime)
{
GameStatistics* info = NULL;
char temp[256] = {0, };
std::string queryStr;
if( m_listGameStatistics.empty() == true ) return;
queryStr = std::string( "SET XACT_ABORT On;" );
queryStr += std::string( "Begin Tran;" );
for(ListGameStatistics::iterator iter = m_listGameStatistics.begin() ; iter != m_listGameStatistics.end() ; iter++ )
{
info = *iter;
for(int i=0;i<eSTATISTIC_MAX + 1;i++){
if(m_StatisticEnumCode.uiEnumStatistic[i]!=0 && info->ui64Statistics[i]>0){
memset(temp, 0x00, 256);
sprintf( temp, "EXEC USP_Day_Statistics_ItemAction_INSERT '%s', %d, %d, %d, %I64d;\r\n",
dateTime,
m_StatisticEnumCode.uiEnumStatistic[i],
info->ti_worldID,
info->ti_channelID,
info->ui64Statistics[i]);
queryStr += std::string( temp );
// 초기화
info->ui64Statistics[i] = 0;
}
}
}
queryStr += std::string( "IF @@Error <> 0 RollBack Tran Else Commit Tran;" );
queryStr += std::string( "SET XACT_ABORT Off;" );
m_dbcWops.Query( 0, queryStr.data() );
}
void Database::SP_CURRENT_RTTAgent_INSERT( char* dateTime )
{
ServerInfo* serverInfo = NULL;
char temp[256] = {0, };
std::string queryStr;
//m_dbcWops.Query( 0, "SET XACT_ABORT On;Begin Tran;EXEC USP_CURRENT_USER_INSERT '2006-07-14 17:07:35', 1, 1, 2, 1, 100, 110, 0;IF @@Error <> 0 RollBack Tran Else Commit Tran;SET XACT_ABORT Off;" );
queryStr = std::string( "SET XACT_ABORT On;" );
queryStr += std::string( "Begin Tran;" );
queryStr += std::string( "Delete From TB_CurrentTimeRTTAgentHitchLog;" );
for(ListServerInfo::iterator iter = m_listServerInfo.begin() ; iter != m_listServerInfo.end() ; iter++ ){
serverInfo = *iter;
//char szFormat[12];memset(szFormat, 0x00, 12);
// 장애 검사
bool bChecker = false;
DWORD dwParentHistoryIDX = 0;
DWORD dwWarning = 0;
if(serverInfo->certifiedRTTAgent==1){ // 장애가 발생한 경우
bChecker = true;
dwWarning = RTTA_NOT_RESPONSE;
//strcpy(szFormat, MSG_RTTA_NOT_RESPONSE);
// DB에 기록되었음을 표시한다.
serverInfo->certifiedRTTAgent = 2;
}
else if(serverInfo->certifiedRTTAgent==0 && serverInfo->agentParentHistoryIDX!=0){ // 장애가 복구된경우
bChecker = true;
dwWarning = RTTA_RESPONSE;
//strcpy(szFormat, MSG_RTTA_RESPONSE);
dwParentHistoryIDX = serverInfo->agentParentHistoryIDX;
serverInfo->agentParentHistoryIDX = 0;
}
if(bChecker==true){ // 장애 및 복구 로그를 남긴다.
eXtreme::RecordSet rec;
// return parameter bind
if(dwWarning==RTTA_NOT_RESPONSE){
rec.BindParameter(&serverInfo->agentParentHistoryIDX, "", adInteger, adParamReturnValue, sizeof(int), "");
}
// input parameter bind
rec.BindParameter(NULL, "@WorldID" , adTinyInt, adParamInput, 1 , _bstr_t(serverInfo->ti_WorldID ));
rec.BindParameter(NULL, "@ChannelID" , adTinyInt, adParamInput, 1 , _bstr_t(serverInfo->ti_ChannelID ));
rec.BindParameter(NULL, "@ServerType" , adTinyInt, adParamInput, 1 , _bstr_t(serverInfo->ti_ServerType));
rec.BindParameter(NULL, "@ServerID" , adTinyInt, adParamInput, 1 , _bstr_t(serverInfo->ti_ServerID ));
rec.BindParameter(NULL, "@HitchDetailID" , adInteger, adParamInput, 4 , _bstr_t(dwWarning ));
rec.BindParameter(NULL, "@Message" , adVarChar, adParamInput, 1 , _bstr_t(" " ));
rec.BindParameter(NULL, "@RegisterDate" , adVarChar, adParamInput, (long)strlen(dateTime), _bstr_t(dateTime ));
rec.BindParameter(NULL, "@ParentHistoryIDX", adInteger, adParamInput, 4 , _bstr_t(dwParentHistoryIDX ));
// call storedProcedure
m_dbcWops.CallStoredProcedure(&rec, "USP_AddWarningHistoryForWopsRelation");
SendErrorNotifyNTF( serverInfo->ti_WorldID,
serverInfo->ti_ChannelID,
serverInfo->ti_ServerType,
serverInfo->ti_ServerID,
dwWarning,
dateTime,
MSG_RTTA_NOT_RESPONSE );
}
{// 현재 상태 기록
sprintf( temp, "EXEC USP_CURRENT_RTTAgent_INSERT '%s', %d, %d, %d, %d, %d;",
dateTime,
serverInfo->ti_WorldID,
serverInfo->ti_ChannelID,
serverInfo->ti_ServerType,
serverInfo->ti_ServerID,
( serverInfo->certifiedRTTAgent == 0 ? 0 : RTTA_NOT_RESPONSE ) );
queryStr += std::string( temp );
}
}
queryStr += std::string( "IF @@Error <> 0 RollBack Tran Else Commit Tran;" );
queryStr += std::string( "SET XACT_ABORT Off;" );
m_dbcWops.Query( 0, queryStr.data() );
}
void Database::SP_CURRENT_RTTS_UPDATE( char* dateTime )
{
char mbcs[256] = {0, };
if( m_svrInfoRTTS == 0 ) return;
sprintf( mbcs, "{call USP_CURRENT_RTTS_UPDATE('%s', %d, %d, %d, %d)}",
dateTime,
m_svrInfoRTTS->ti_WorldID,
m_svrInfoRTTS->ti_ChannelID,
m_svrInfoRTTS->ti_ServerType,
m_svrInfoRTTS->ti_ServerID );
m_dbcWops.Query( 0, mbcs );
}
void Database::GetUpdateTime()
{
TB_UpdateTime record;
m_dbcWops.Query( &record, "SELECT ti_ConnectCountUpdateTime, ti_ResourceUpdateTime, ti_WopsRelationUpdateTime, "
"ti_MoneyUpdateTime, ti_MoneyGap FROM TB_UpdateTime" );
if( record.IsEndRecord() == false )
{
m_gapConnectCount = record.record.ti_ConnectCountUpdateTime * 1000;
m_gapResource = record.record.ti_ResourceUpdateTime * 1000;
m_gapWopsRelation = record.record.ti_WopsRelationUpdateTime * 1000;
m_stdMoneyGap = record.record.ti_MoneyGap; // 이건 % 기준이다.
RTTAgent::m_updateUserMoneyTick = record.record.ti_MoneyUpdateTIme * 1000;
RTTAgent::m_updateBattleZoneInfoTick = record.record.ti_MoneyUpdateTIme * 1000;
}
else
{
m_gapConnectCount = 0;
m_gapResource = 0;
m_gapWopsRelation = 0;
}
}
/*
[2006.04.20] modify by guiun
서버 탐색 방법 변경
*/
void Database::ClearLaunchProcessStatus( short worldID, short channelID, short serverType, short serverID )
{
ServerInfo* info = NULL;
for(ListServerInfo::iterator iter = m_listServerInfo.begin() ; iter != m_listServerInfo.end() ; iter++ )
{
info = *iter;
if(worldID==0 || worldID==info->ti_WorldID){ // 전체 world 또는 특정 world
if(channelID==CHANNEL_ALL || channelID==info->ti_ChannelID){ // 전체 channel 또는 특정 channel
if(serverType==0 || serverType==info->ti_ServerType){ // 전체 servertype 또는 특정 servertype
if(serverID==0 || serverID==info->ti_ServerID){ // 전체 serverid 또는 특정 serverid
info->launchProcessStatus = 0;
}
}
}
}
/*
// 해당 서버만 검색한다.
if( worldID == 0 ||
( worldID != 0 && channelID == 0 && info->ti_WorldID == worldID ) ||
( worldID != 0 && channelID != 0 && info->ti_WorldID == worldID && info->ti_ChannelID == channelID ) )
{
info->launchProcessStatus = 0;
}
*/
}
}
/*
[2006.04.20] modify by guiun
서버 탐색 방법 변경
*/
bool Database::CheckLaunchProcessStatus( short worldID,
short channelID,
short serverType,
short serverID,
DWORD result, DWORD* error )
{
ServerInfo* info = NULL;
bool ret = true;
*error = 0;
for(ListServerInfo::iterator iter = m_listServerInfo.begin() ; iter != m_listServerInfo.end() ; iter++ )
{
info = *iter;
if(worldID==0 || worldID==info->ti_WorldID){ // 전체 world 또는 특정 world
if(channelID==CHANNEL_ALL || channelID==info->ti_ChannelID){ // 전체 channel 또는 특정 channel
if(serverType==0 || serverType==info->ti_ServerType){ // 전체 servertype 또는 특정 servertype
if(serverID==0 || serverID==info->ti_ServerID){ // 전체 serverid 또는 특정 serverid
char ipAddress[IP_MAX_LEN] = {0, };
::WideCharToMultiByte( CP_ACP, 0, info->vc_InnerIP, -1, ipAddress, IP_MAX_LEN, 0, 0 );
if(ManagerClient::Instance()->FindClient(ipAddress)==NULL){ // 접속된 Agent가 아니다.
continue;
}
if( result == 0 ){
info->launchProcessStatus = 2; // 에러 발생
}
else if( result == 1 ){
info->launchProcessStatus = 1; // 작업 완료
}
// 에러가 보고된 기록을 찾는다.
if( info->launchProcessStatus == 2 ){
*error = 1;
}
// 아직 결과가 보고되지 않았다면 false를 반환한다.
if( info->launchProcessStatus == 0 ){
ret = false;
}
}
}
}
}
/*
// 해당 서버만 검색한다.
if( checkWorldID == 0 ||
( checkWorldID != 0 && checkChannelID == 0 && info->ti_WorldID == checkWorldID ) ||
( checkWorldID != 0 && checkChannelID != 0 && info->ti_WorldID == checkWorldID && info->ti_ChannelID == checkChannelID ) )
{
if( info->ti_WorldID == worldID && info->ti_ChannelID == channelID &&
info->ti_ServerType == serverType && info->ti_ServerID == serverID )
{
if( result == 0 )
info->launchProcessStatus = 2; // 에러 발생
else if( result == 1 )
info->launchProcessStatus = 1; // 작업 완료
}
// 에러가 보고된 기록을 찾는다.
if( info->launchProcessStatus == 2 )
*error = 1;
// 아직 결과가 보고되지 않았다면 false를 반환한다.
if( info->launchProcessStatus == 0 )
ret = false;
}
*/
}
return ret;
}
/*
[2006.04.20] modify by guiun
서버 패치 정보에 ServerType, ServerID 추가
*/
DWORD Database::MakePatchKey( __int64 wopsKey, DWORD uid, short worldID, short channelID , short serverType, short serverID, short serverTypeForProcess )
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexPatchKey );
PatchKey* key = new PatchKey;
key->bi_wopsKey = wopsKey;
key->i_uid = uid;
key->ti_WorldID = worldID;
key->ti_ChannelID = channelID;
key->ti_ServerType = serverType;
key->ti_ServerID = serverID;
key->ti_ServerTypeForProcess = serverTypeForProcess;
m_listPatchKey.push_back( key );
// 해당 서버정보에서 패치 기록을 초기화한다.
{
ServerInfo* info = NULL;
for(ListServerInfo::iterator iter = m_listServerInfo.begin() ; iter != m_listServerInfo.end() ; iter++ )
{
bool bCmp = false;
info = *iter;
if(worldID==0 || worldID==info->ti_WorldID) // 전체 world 또는 특정 world
{
if(channelID==CHANNEL_ALL || channelID==info->ti_ChannelID) // 전체 channel 또는 특정 channel
{
if(serverType==0 || serverType==info->ti_ServerType) // 전체 servertype 또는 특정 servertype
{
if(serverID==0 || serverID==info->ti_ServerID) // 전체 serverid 또는 특정 serverid
{
bCmp = true;
}
}
}
}
if( bCmp == true )
{
/*
2006.09.19 modify by guiun
패치시 해당 서버의 패치 대상 서버가 존재 하는지 확인을 한다.
1. 해당 서버에 RTTAgent가 실행중인지 확인을 한다.
2. 해당 서버의 패치 대상 서버가 존재 하는지 확인을 한다.
*/
// 해당 서버에 RTTAgent가 실행중인지 확인을 한다.
RTTAgent* pAgent = ManagerClient::Instance()->FindClient(info->ti_WorldID, info->ti_ChannelID, info->ti_ServerType, info->ti_ServerID);
if( NULL != pAgent )
{
bool bPatch = false;
if ( serverTypeForProcess != 0 ) // 해당 서버의 패치 대상 서버가 존재 하는지 확인을 한다.
{
// Process 정보
ServerProcess processList[20];
int size = 0;
char ip[16] = {0, };
::WideCharToMultiByte( CP_ACP, 0, info->vc_InnerIP, -1, ip, 16, 0, 0 );
ip[15] = '\0';
MonitorProcess::Instance()->GetList( info->ti_WorldID,
info->ti_ChannelID,
info->ti_ServerType,
info->ti_ServerID,
ip,
processList,
20,
&size );
for ( int i = 0 ; i < size ; i++ )
{
if( processList[i].ti_ServerTypeForPatch == serverTypeForProcess )
{
bPatch = true;
break;
}
}
}
else // 패치 대상 서버가 전체이므로 패치 대상 서버 등록 여부를 확인 하지 않고 패치를 진행한다.
{
bPatch = true;
}
if( bPatch )
{
info->patchStatus = MSG_RTTG_PATCHRESULT_ANS::ERROR_NONE;
info->bPatchCompleted = false;
}
else // 패치 대상 검색 실패
{
OutputDebug( "[Database::MakePatchKey] Not Found from MonitorProcess %d, %d, %d, %d, %S\n",
info->ti_WorldID,
info->ti_ChannelID,
info->ti_ServerType,
info->ti_ServerID,
info->i_InnerPort );
}
}
else // RTTAgent가 실행중이 아니므로 실패
{
OutputDebug( "[Database::MakePatchKey] Not Found from ManagerClient %d, %d, %d, %d, %S\n",
info->ti_WorldID,
info->ti_ChannelID,
info->ti_ServerType,
info->ti_ServerID,
info->i_InnerPort );
}
}
}
}
return ( DWORD )( u_int64 )key;
}
/*
[2006.04.25] modify by guiun
list에서 patchkey를 꺼내고 list에서 해당 patchkey를 삭제
*/
PatchKey* Database::GetPatchKey( DWORD patchKey )
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexPatchKey );
PatchKey* key = NULL;
for(ListPatchKey::iterator iter = m_listPatchKey.begin() ; iter != m_listPatchKey.end() ; iter++ )
{
key = *iter;
if( patchKey == (DWORD)( u_int64 )key ){
return key;
}
}
return 0;
}
DWORD Database::SetPatchResult( wchar_t* ip, __int64 wopsKey, DWORD dwServerTypeForProcess, DWORD result, BYTE byIndex , const char* lpVersion)
{
ServerInfo* info = NULL;
for(ListServerInfo::iterator iter = m_listServerInfo.begin() ; iter != m_listServerInfo.end() ; iter++ )
{
info = *iter;
if( wcscmp( info->vc_InnerIP, ip ) == 0)
{
if(info->patchStatus==MSG_RTTG_PATCHRESULT_ANS::ERROR_NONE){ // 처음 error code를 받은 경우
info->patchStatus = result;
}
else{
// 기존 에러코드가 존재 하고 결과로 받은 에러코드가 성공이 아닌경우
// 최종 에러코드가 기록이 된다.
if(result!=MSG_RTTG_PATCHRESULT_ANS::ERROR_PATCHSUCCESS){
info->patchStatus = result;
}
}
if(byIndex==0) info->bPatchCompleted = true;
break;
}
}
// 패치 결과를 DB에 Update
char keyStr[64] = {0, };
sprintf( keyStr, "%I64d", wopsKey );
// try
// {
// 2006. 7. 13 김종호
// QueryExternal()함수의 리턴값을 저장(예외 발생시 false)
bool bException = false;
switch( result )
{
case MSG_RTTG_PATCHRESULT_ANS::ERROR_PROCESSRUN:
bException = QueryExternal( "{call USP_AddPatchLog('%s', %d, %d, %d, %d, %d, %d, '%s')}", keyStr,
info->ti_WorldID, info->ti_ChannelID, info->ti_ServerType, info->ti_ServerID, dwServerTypeForProcess,PATCH_PROCESSRUNNING, lpVersion );
break;
case MSG_RTTG_PATCHRESULT_ANS::ERROR_FTPCONNECT_FAIL:
bException = QueryExternal( "{call USP_AddPatchLog('%s', %d, %d, %d, %d, %d, %d, '%s')}", keyStr,
info->ti_WorldID, info->ti_ChannelID, info->ti_ServerType, info->ti_ServerID, dwServerTypeForProcess, PATCH_FTPCONNECT_FAIL, lpVersion );
break;
case MSG_RTTG_PATCHRESULT_ANS::ERROR_DOWNLOAD_FAIL:
bException = QueryExternal( "{call USP_AddPatchLog('%s', %d, %d, %d, %d, %d, %d, '%s')}", keyStr,
info->ti_WorldID, info->ti_ChannelID, info->ti_ServerType, info->ti_ServerID, dwServerTypeForProcess, PATCH_DOWNLOAD_FAIL, lpVersion );
break;
case MSG_RTTG_PATCHRESULT_ANS::ERROR_FILENOTFOUND:
bException = QueryExternal( "{call USP_AddPatchLog('%s', %d, %d, %d, %d, %d, %d, '%s')}", keyStr,
info->ti_WorldID, info->ti_ChannelID, info->ti_ServerType, info->ti_ServerID, dwServerTypeForProcess, PATCH_FILESEARCH_FAIL, lpVersion );
break;
case MSG_RTTG_PATCHRESULT_ANS::ERROR_PATCHSUCCESS:
bException = QueryExternal( "{call USP_AddPatchLog('%s', %d, %d, %d, %d, %d, %d, '%s')}", keyStr,
info->ti_WorldID, info->ti_ChannelID, info->ti_ServerType, info->ti_ServerID, dwServerTypeForProcess, PATCH_SUCCESS, lpVersion );
break;
case MSG_RTTG_PATCHRESULT_ANS::ERROR_INVALID_SERVERTYPE:
/*
특정 타입에 대하여 전체 서버에게 보내는 경우 RTTS가 각 서버가 가지고 있는 타입을 알수가 없다.
따라서 이 에러코드는 패치 클라이언트가 특정 타입의 서버를 가지고 있지 않는 경우가 생기므로
패치 클라이언트에서 에러로 전송되지만
아무런 처리를 하지 않는다.
*/
break;
default:
OutputDebug( "Not defined result code(=%d).\n", result );
break;
}
// }
// catch( eXtreme::ExceptionDBC& )
// {
// return 0;
// }
/*
if( !bException )
{
return 0; // 예외발생시...
}
*/
return info->patchStatus;
}
bool Database::IsPatchCompleted(short /*worldID*/, short /*channelID*/, short /*serverType*/, short /*serverID*/ )
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexPatchKey );
ServerInfo* info = NULL;
bool bRetValue = true;
for(ListServerInfo::iterator iter = m_listServerInfo.begin() ; iter != m_listServerInfo.end() ; iter++ )
{
info = *iter;
if( info->bPatchCompleted == false )
{
bRetValue = false;
}
}
return bRetValue;
//ListServerInfo::iterator iter;
//ServerInfo* info;
//
//char szAddress[IP_MAX_LEN];
//for( iter = m_listServerInfo.begin() ; iter != m_listServerInfo.end() ; iter++ )
//{
// info = *iter;
// memset(szAddress, 0x00, IP_MAX_LEN);
// ::WideCharToMultiByte( CP_ACP, 0, info->vc_InnerIP, -1, szAddress, IP_MAX_LEN, 0, 0 );
//
// if(ManagerClient::Instance()->FindClient(szAddress)!=NULL){
// if(worldID==0 || worldID==info->ti_WorldID){ // 전체 world 또는 특정 world
// if(channelID==CHANNEL_ALL || channelID==info->ti_ChannelID){ // 전체 channel 또는 특정 channel
// if(serverType==0 || serverType==info->ti_ServerType){ // 전체 servertype 또는 특정 servertype
// if(serverID==0 || serverID==info->ti_ServerID){ // 전체 serverid 또는 특정 serverid
// if(info->bPatchCompleted==false){
// return false;
// }
// }
// }
// }
// }
// }
// /*
// // 해당 서버만 검색한다.
// if( worldID == 0 ||
// ( worldID != 0 && channelID == 0 && info->ti_WorldID == worldID ) ||
// ( worldID != 0 && channelID != 0 && info->ti_WorldID == worldID && info->ti_ChannelID == channelID ) )
// {
// // 패치가 시작되지 않았거나 진행중인 경우
// if( info->patchStatus == MSG_RTTG_PATCHRESULT_ANS::ERROR_NONE )
// return false;
// }
// */
//}
//return true;
}
void Database::BroadcastForPatch( char* buffer, int size )
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexPatchKey );
ServerInfo* info = NULL;
for(ListServerInfo::iterator iter = m_listServerInfo.begin() ; iter != m_listServerInfo.end() ; iter++ )
{
info = *iter;
if( info->bPatchCompleted == false && info->patchStatus == MSG_RTTG_PATCHRESULT_ANS::ERROR_NONE)
{
RTTAgent* pAgent = ManagerClient::Instance()->FindClient(info->ti_WorldID, info->ti_ChannelID, info->ti_ServerType, info->ti_ServerID);
if( pAgent != NULL )
{
pAgent->SendPacket( buffer, size);
OutputDebug( "[Database::BroadcastForPatch] %d, %d, %d, %d, %S\n",
info->ti_WorldID,
info->ti_ChannelID,
info->ti_ServerType,
info->ti_ServerID,
info->i_InnerPort );
}
else
{
OutputDebug( "[Database::BroadcastForPatch] Not Found from ManagerClient %d, %d, %d, %d, %S\n",
info->ti_WorldID,
info->ti_ChannelID,
info->ti_ServerType,
info->ti_ServerID,
info->i_InnerPort );
}
}
}
}
void Database::ClearPatchKeyAll()
{
eXtreme::Guard < eXtreme::Mutex > lock( m_mutexPatchKey );
{ // 서버 정보에 있는 패치 정보를 초기화 한다.
ServerInfo* info = NULL;
for(ListServerInfo::iterator iter = m_listServerInfo.begin() ; iter != m_listServerInfo.end() ; iter++ )
{
info = *iter;
info->bPatchCompleted = true;
}
}
{ // 기존에 존재하는 패치 키를 삭제 한다.
PatchKey* info = NULL;
for(ListPatchKey::iterator iter = m_listPatchKey.begin() ; iter != m_listPatchKey.end() ; iter++ )
{
info = *iter;
delete info;
}
m_listPatchKey.clear();
}
}
void Database::Run()
{
char dateTime[127] = {0, };
char tmp[8] = {0, };
// 현재 Tick으로 초기화
DWORD preTick_Resource = ::GetTickCount();
DWORD preTick_UserCount = ::GetTickCount();
DWORD preTick_UpdateTime = ::GetTickCount();
DWORD preTick_RTTAgent = ::GetTickCount();
DWORD preTick_RTTServer = ::GetTickCount();
DWORD preTick_MasterServer = ::GetTickCount();
DWORD dwTickGameStatistics = ::GetTickCount();
// DB 사용 유무를 설정
::GetPrivateProfileString( "DBSetting", "Enable_UserCount", "err", tmp, 8, SERVERINFO_FILENAME );
bool enableUserCount = ( ::strncmp( tmp, "true", 8 ) == 0 );
::GetPrivateProfileString( "DBSetting", "Enable_SystemResource", "err", tmp, 8, SERVERINFO_FILENAME );
bool enableSystemResource = ( ::strncmp( tmp, "true", 8 ) == 0 );
::GetPrivateProfileString( "DBSetting", "Enable_UpateTime", "err", tmp, 8, SERVERINFO_FILENAME );
bool enableUpdateTime = ( ::strncmp( tmp, "true", 8 ) == 0 );
::GetPrivateProfileString( "DBSetting", "Enable_RTTAgent", "err", tmp, 8, SERVERINFO_FILENAME );
bool enableRTTAgent = ( ::strncmp( tmp, "true", 8 ) == 0 );
//DWORD dwCurrentTick = 0;
while( 1 ){
if( ::WaitForSingleObject( m_eventKill, 1000 ) == WAIT_OBJECT_0 ) break;
//dwCurrentTick = ::GetTickCount();
// if( m_flagReconnectDB == true )
// {
// m_flagReconnectDB = ( Initialize() == true ? false : true );
// continue;
// }
// 2006. 7. 14 김종호
// 위 소스를 아래와 같이 수정
if( m_dbcWops.GetState() == adStateClosed )
{
Instance()->Finalize();
if(false==Initialize())
{
OutputDebug( "[Database::Run] DB 연결 실패.\n" );
Sleep(5000);
continue;
}
}
{// 현재 날짜
SYSTEMTIME sysTime;
::GetLocalTime( &sysTime );
sprintf( dateTime, "%d-%02d-%02d %02d:%02d:%02d", sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond );
}
// 동시접속자 수 갱신
if( enableUserCount == true && ::GetTickCount() - preTick_UserCount > m_gapConnectCount )
{
/*
[2006.04.17] Addy by guiun
*/
bool bCheckAlive = false; // 동접 값 입력시 이 값으 true이면 주기적으로 동접값을 받고 있는 확인한다.
// Master 서버 동접 값이 주기적으로 전송 되고 있는지 확인 한다.
if(::GetTickCount() - preTick_MasterServer > MASTER_CHECK_TIME)
{
bCheckAlive = true;
}// End Master Server 동접 값 확인
//* 1. 개발쪽에 패치때는 DB업데이트를 하지 않으므로 1~5까지를 주석처리 후 빌드한다
SP_CURRENT_USER_INSERT( dateTime, bCheckAlive );
SP_CURRENT_BattleZone_INSERT( dateTime );
SP_CURRENT_Money_INSERT( dateTime );
//*/
if(bCheckAlive)
{
preTick_MasterServer = ::GetTickCount();
}
preTick_UserCount = ::GetTickCount();
}
// System Resource 갱신
if( enableSystemResource == true && ::GetTickCount() - preTick_Resource > m_gapResource )
{
//* 2.
SP_CURRENT_RESOURCE_INSERT( dateTime );
//*/
//ClearResourceInfo();
preTick_Resource = ::GetTickCount();
}
// RTTAgent 갱신
if( enableRTTAgent == true && ::GetTickCount() - preTick_RTTAgent > m_gapWopsRelation )
{
//SP_CURRENT_RTTS_UPDATE( dateTime );
//* 3.
SP_CURRENT_RTTAgent_INSERT( dateTime );
//*/
preTick_RTTAgent = ::GetTickCount();
}
/*
[2006.04.13] Modify by guiun
RTTS 갱신은 5sec로 고정한다.
*/
if(::GetTickCount() - preTick_RTTServer > 5000 )
{
//* 4.
SP_CURRENT_RTTS_UPDATE( dateTime );
//*/
preTick_RTTServer = ::GetTickCount();
}
/* [2006.06.29] Add by guiun
게임 통계 추가
*/
if(::GetTickCount() - dwTickGameStatistics > 60000)
{
//* 5.
SP_CURRENT_GameStatistics_INSERT( dateTime );
//*/
dwTickGameStatistics = ::GetTickCount();
}
// Update 시간 갱신
if( enableUpdateTime == true && ::GetTickCount() - preTick_UpdateTime > 30000 )
{
GetUpdateTime();
ReloadWarningCanon();
preTick_UpdateTime = ::GetTickCount();
}
}
}