#include "stdafx.h" #include "UserStatistics.h" #include #include #include #include #include #include #include #include const TCHAR* g_szAppName = _T("HANGAME_SEND_USER_INFO"); CUserStatistics& CUserStatistics::GetInstance() { static CUserStatistics userStatistics; return userStatistics; } CUserStatistics::CUserStatistics() { SetSetupFileName(_T("./RylSetupServerGroup.ini")); Load(); } CUserStatistics::~CUserStatistics() { } void CUserStatistics::SetSetupFileName(const TCHAR* szFileName) { if(0 != szFileName) { _sntprintf(m_szSetupFileName, MAX_PATH - 1, "%s", szFileName); m_szSetupFileName[MAX_PATH - 1] = 0; } } bool CUserStatistics::Load() { StatisticsLock::Syncronize sync(m_Lock); TCHAR szKeyName[MAX_PATH]; TCHAR szValue[MAX_PATH]; m_ServerGroupNames.clear(); unsigned long dwMaxServerGroup = GetPrivateProfileInt(g_szAppName, "MAX_GROUP_NAME", 0, m_szSetupFileName); for(unsigned long dwCount = 0; dwCount < dwMaxServerGroup; ++dwCount) { _sntprintf(szKeyName, MAX_PATH - 1, "GROUP_KEY%u", dwCount); szKeyName[MAX_PATH - 1] = 0; unsigned long dwKey = GetPrivateProfileInt(g_szAppName, szKeyName, 0xFFFFFFFF, m_szSetupFileName); if(dwKey != 0xFFFFFFFF) { _sntprintf(szKeyName, MAX_PATH - 1, "GROUP_NAME%u", dwCount); szKeyName[MAX_PATH - 1] = 0; GetPrivateProfileString(g_szAppName, szKeyName, 0, szValue, MAX_PATH, m_szSetupFileName); m_ServerGroupNames.insert(ServerGroupNames::value_type(dwKey, szValue)); } } GetPrivateProfileString(g_szAppName, "HANGAME_SERVER_DOMAIN", 0, szValue, MAX_PATH, m_szSetupFileName); unsigned short usPort = static_cast( GetPrivateProfileInt(g_szAppName, "HANGAME_SERVER_PORT", 0, m_szSetupFileName)); hostent* lphost = gethostbyname(szValue); if (0 != lphost) { for (int nCount = 0; 0 != lphost->h_addr_list[nCount]; ++nCount ) { m_HangameAddress.push_back( INET_Addr(*(in_addr*)lphost->h_addr_list[nCount], usPort)); } } return true; } void CUserStatistics::InternalSetUserNum(unsigned long dwRunID, unsigned long dwServerID, int nCurrentUserNum) { // ServerID ±ÔÄ¢ üũ dwServerID SERVER_ID serverID; serverID.dwID = dwServerID; if(0 <= serverID.GetChannel() && 0 <= serverID.GetGroup() && 0 <= serverID.GetZone()) { UserNumTable::iterator pos = m_CurrentUsers.find(dwServerID); if(pos != m_CurrentUsers.end()) { // °ª ¼öÁ¤ pos->second = nCurrentUserNum; } else { // °ª »ðÀÔ pos = m_CurrentUsers.insert(pos, UserNumTable::value_type(dwServerID, nCurrentUserNum)); m_RunIDTable.insert(RunIDTable::value_type(dwRunID, pos)); } } } int CUserStatistics::GetUserNum(unsigned long dwServerID) { StatisticsLock::Syncronize sync(m_Lock); UserNumTable::iterator find = m_CurrentUsers.find(dwServerID); return (find != m_CurrentUsers.end()) ? find->second : 0; } int CUserStatistics::GetTotalUserNum() { StatisticsLock::Syncronize sync(m_Lock); UserNumTable::iterator pos = m_CurrentUsers.begin(); UserNumTable::iterator end = m_CurrentUsers.end(); int nTotalUser = 0; for(; pos != end; ++pos) { int nCurrentUser = pos->second; if(0 < nCurrentUser) { nTotalUser += pos->second; } } return nTotalUser; } int CUserStatistics::GetGroupUserNum(char cGroupNum) { StatisticsLock::Syncronize sync(m_Lock); UserNumTable::iterator pos = m_CurrentUsers.begin(); UserNumTable::iterator end = m_CurrentUsers.end(); int nTotalUser = 0; SERVER_ID serverID; for(; pos != end; ++pos) { serverID.dwID = pos->first; if(cGroupNum == serverID.GetGroup()) { int nCurrentUser = pos->second; if(0 < nCurrentUser) { nTotalUser += pos->second; } } } return nTotalUser; } void CUserStatistics::InternalClearRunID_UserNum(unsigned long dwRunID) { std::pair resultPair = m_RunIDTable.equal_range(dwRunID); RunIDTable::iterator pos = resultPair.first; for(; pos != resultPair.second; ++pos) { if(0 != pos->second->second) { pos->second->second = 0; } } } void CUserStatistics::InternalClearGroupUserNum(unsigned char cGroupNum) { UserNumTable::iterator pos = m_CurrentUsers.begin(); UserNumTable::iterator end = m_CurrentUsers.end(); SERVER_ID serverID; for(; pos != end; ++pos) { serverID.dwID = pos->first; if(cGroupNum == serverID.GetGroup()) { pos->second = 0; } } } void CUserStatistics::SerializeIn(unsigned long dwRunID, ServerManage::UserNumPair* lpUserNumPair, unsigned long dwPairNum) { if(0 != lpUserNumPair) { StatisticsLock::Syncronize sync(m_Lock); ServerManage::UserNumPair* lpUserNumPairEnd = lpUserNumPair + dwPairNum; for(; lpUserNumPair != lpUserNumPairEnd; ++lpUserNumPair) { InternalSetUserNum(dwRunID, lpUserNumPair->m_dwServerID, lpUserNumPair->m_nUserNum); } } } void CUserStatistics::SendStatisticsToHanGame() { if(0 == GetPrivateProfileInt(g_szAppName, "SEND_HANGAME_INFO", 0, m_szSetupFileName)) { // Àü¼ÛÇÏÁö ¾Ê´Â´Ù. return; } char szGameID[256]; GetPrivateProfileString(g_szAppName, "SEND_GAME_ID", _T("RYL"), szGameID, 256, m_szSetupFileName); UserNumTable CurrentUsers; { StatisticsLock::Syncronize sync(m_Lock); CurrentUsers = m_CurrentUsers; } const int MAX_BUFFER = 3192; char szBuffer[MAX_BUFFER]; SERVER_ID ServerID; int nUserNum = 0; int nLength = 0; size_t nMaxGroupName = m_ServerGroupNames.size(); SOCKADDR_IN ServerAddr; memset(&ServerAddr, 0, sizeof(SOCKADDR_IN)); UserNumTable::iterator pos = CurrentUsers.begin(); UserNumTable::iterator end = CurrentUsers.end(); for(; pos != end; ++pos) { ServerID.dwID = pos->first; nUserNum = pos->second; if(ServerID.GetZone() - 1 < 0 || ServerID.GetChannel() < 0) { } else if(0 < nUserNum) { ServerGroupNames::iterator pos = m_ServerGroupNames.find(ServerID.GetGroup()); if(pos != m_ServerGroupNames.end()) { // TODO : Sparrowhawk. // ¿ô±â´Â »óȲÀÌ.. ù Á¸ÀÎ GrandCost´Â Á¸ ¹øÈ£°¡ 1ÀÌ´Ù. // ±×·±µ¥ µ¿Á¢ ÆäÀÌÁö º¸³¾ ¶§´Â Á¸ ¹øÈ£°¡ 0À¸·Î º¸³»¾ß ÇÑ´Ù. // GetServerSessionÀ¸·Î ¾òÀ» ¶§µµ ¸¶Âù°¡ÁöÀÌ´Ù. nLength = _snprintf(szBuffer, MAX_BUFFER, "GET /gamestatic/gameconn.nhn?m=gameconn&gameid=%s&servername=%s-%d-%d&conncount=%d\n\n", szGameID, pos->second.c_str(), ServerID.GetZone() - 1, ServerID.GetChannel(), nUserNum); // Àü¼Û AddressList::iterator pos = m_HangameAddress.begin(); AddressList::iterator end = m_HangameAddress.end(); bool bSucceeded = false; for (; pos != end && !bSucceeded; ++pos) { INET_Addr& address = *pos; SOCKET hSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, WSA_FLAG_OVERLAPPED); if (INVALID_SOCKET == hSocket) { ERRLOG1(g_Log, "Hangame user send failed : socket create failed - %d", WSAGetLastError()); } else if (SOCKET_ERROR == connect(hSocket, &address.get_addr(), address.get_size())) { ERRLOG1(g_Log, "Hangame user send failed : connect failed - %d", WSAGetLastError()); } else if (SOCKET_ERROR == send(hSocket, szBuffer, nLength, 0)) { ERRLOG1(g_Log, "Hangame user send failed : send failed - %d", WSAGetLastError()); } else { INFLOG2(g_Log, "'%s':%d bytes send complete", szBuffer, nLength); bSucceeded = true; } shutdown(hSocket, SD_SEND); closesocket(hSocket); } } } } } void CUserStatistics::SendStatisticsToStatServer() { int nSendGlobal = GetPrivateProfileInt("STATSERVER_INFO", "SEND_STAT_SERVER_1ST", 0, m_szSetupFileName); int nSendLocal = GetPrivateProfileInt("STATSERVER_INFO", "SEND_STAT_SERVER_2ND", 0, m_szSetupFileName); int nNation = GetPrivateProfileInt("GENERAL", "NATION_INDEX", 0, m_szSetupFileName); if((0 == nSendGlobal) && (0 == nSendLocal)) { return; } if(UCHAR_MAX < nNation) { ERRLOG1(g_Log, "Nation index is invalid: NationIndex-%d", nNation); return; } SERVER_ID ServerID; int nUserNum = 0; UserNumTable CurrentUsers; { StatisticsLock::Syncronize sync(m_Lock); CurrentUsers = m_CurrentUsers; } const int MAX_USER_STAT = 1000; const int BUFFER_SIZE = sizeof(ServerManage::PktUserStat) + sizeof(ServerManage::UserStatData) * MAX_USER_STAT; char szBuffer[BUFFER_SIZE]; ServerManage::PktUserStat* lpPktUserStat = reinterpret_cast(szBuffer); ServerManage::UserStatData* lpUserStatData = reinterpret_cast(lpPktUserStat + 1); unsigned short nUserStatData = 0; SYSTEMTIME stCurrentTime; GetLocalTime(&stCurrentTime); _snprintf(lpPktUserStat->m_szSendingTime, ServerManage::PktUserStat::MAX_DATE, "%04d-%02d-%02d %02d:%02d:%02d", stCurrentTime.wYear, stCurrentTime.wMonth, stCurrentTime.wDay, stCurrentTime.wHour, stCurrentTime.wMinute, stCurrentTime.wSecond); UserNumTable::iterator pos = CurrentUsers.begin(); UserNumTable::iterator end = CurrentUsers.end(); const int MAX_BUFFER = 256; char szGlobalStatServerIP[MAX_BUFFER], szLocalStatServerIP[MAX_BUFFER]; GetPrivateProfileString("STATSERVER_INFO", "STAT_SERVER_1ST_IP", 0, szGlobalStatServerIP, MAX_BUFFER, m_szSetupFileName); GetPrivateProfileString("STATSERVER_INFO", "STAT_SERVER_2ND_IP", 0, szLocalStatServerIP, MAX_BUFFER, m_szSetupFileName); GET_MULTI_DISPATCH(lpGlobalStatDispatch, inet_addr(szGlobalStatServerIP), CStatServerMultiDispatch, CStatServerMultiDispatch::GetDispatchTable()); GET_MULTI_DISPATCH(lpLocalStatDispatch, inet_addr(szLocalStatServerIP), CStatServerMultiDispatch, CStatServerMultiDispatch::GetDispatchTable()); // µ¿Á¢ Á¤º¸ ¼öÁý for(; pos != end; ++pos) { ServerID.dwID = pos->first; nUserNum = pos->second; if(nUserNum < 0) { nUserNum = 0; } if(ServerID.GetZone() - 1 < 0 || ServerID.GetChannel() < 0) { ERRLOG1(g_Log, "Invalid serverID: %u", ServerID.dwID); } else if(CServerSetup::GameServer == ServerID.GetType()) { lpUserStatData->m_dwServerID = ServerID.dwID; lpUserStatData->m_nNation = nNation; lpUserStatData->m_nUserNum = nUserNum; INFLOG3(g_Log, "[UserStat Sended] NationCode: %d/ServerID: 0x%08x/UserNum: %d", nNation, ServerID.dwID, nUserNum); ++lpUserStatData; ++nUserStatData; } } // Á¤º¸ Àü¼Û if(nUserStatData == MAX_USER_STAT - 1) { lpPktUserStat->m_usUserStatDataNum = nUserStatData; if((NULL != lpGlobalStatDispatch) && (1 == nSendGlobal)) { lpGlobalStatDispatch->GetSendStream().WrapCompress(szBuffer, sizeof(ServerManage::PktUserStat) + sizeof(ServerManage::UserStatData) * nUserStatData, ServerManage::CMD::UPDATE_USER_STATUS, 0, 0); } if((NULL != lpLocalStatDispatch) && (1 == nSendLocal)) { lpLocalStatDispatch->GetSendStream().WrapCompress(szBuffer, sizeof(ServerManage::PktUserStat) + sizeof(ServerManage::UserStatData) * nUserStatData, ServerManage::CMD::UPDATE_USER_STATUS, 0, 0); } lpUserStatData = reinterpret_cast(lpPktUserStat + 1); nUserStatData = 0; } if(0 < nUserStatData) { lpPktUserStat->m_usUserStatDataNum = nUserStatData; if((NULL != lpGlobalStatDispatch) && (1 == nSendGlobal)) { lpGlobalStatDispatch->GetSendStream().WrapCompress(szBuffer, sizeof(ServerManage::PktUserStat) + sizeof(ServerManage::UserStatData) * nUserStatData, ServerManage::CMD::UPDATE_USER_STATUS, 0, 0); } if((NULL != lpLocalStatDispatch) && (1 == nSendLocal)) { lpLocalStatDispatch->GetSendStream().WrapCompress(szBuffer, sizeof(ServerManage::PktUserStat) + sizeof(ServerManage::UserStatData) * nUserStatData, ServerManage::CMD::UPDATE_USER_STATUS, 0, 0); } } } void CUserStatistics::CheckClearUser(PktBase* lpPktBase) { StatisticsLock::Syncronize sync(m_Lock); if(sizeof(ServerManage::ManageCommand) <= lpPktBase->GetLen()) { ServerManage::ManageCommand* lpManageCommand = reinterpret_cast(lpPktBase); int nProcessStatusNum = int(lpManageCommand->usDataLen / sizeof(ServerManage::ProcessStatus)); if(sizeof(ServerManage::ManageCommand) + lpManageCommand->usDataLen == lpPktBase->GetLen() && lpManageCommand->usDataLen == nProcessStatusNum * sizeof(ServerManage::ProcessStatus)) { ServerManage::ProcessStatus* lpProcessStatus = reinterpret_cast(lpManageCommand + 1); ServerManage::ProcessStatus* lpProcessStatusEnd = lpProcessStatus + nProcessStatusNum; for(; lpProcessStatus != lpProcessStatusEnd; ++lpProcessStatus) { if(0 == (ServerManage::PROCESS_RUNNING & lpProcessStatus->m_dwStatusFlags)) { InternalClearRunID_UserNum(lpProcessStatus->m_dwRunID); } } } } }