server/game/src/desc_manager.cpp

535 lines
11 KiB
C++

#include "stdafx.h"
#include "config.h"
#include "utils.h"
#include "crc32.h"
#include "desc.h"
#include "desc_p2p.h"
#include "desc_client.h"
#include "desc_manager.h"
#include "char.h"
#include "protocol.h"
#include "messenger_manager.h"
#include "p2p.h"
#include "dev_log.h"
#include "ClientPackageCryptInfo.h"
struct valid_ip
{
const char * ip;
BYTE network;
BYTE mask;
};
static struct valid_ip admin_ip[] =
{
{ "210.123.10", 128, 128 },
{ "\n", 0, 0 }
};
int IsValidIP(struct valid_ip* ip_table, const char *host)
{
int i, j;
char ip_addr[256];
for (i = 0; *(ip_table + i)->ip != '\n'; ++i)
{
j = 255 - (ip_table + i)->mask;
do
{
snprintf(ip_addr, sizeof(ip_addr), "%s.%d", (ip_table + i)->ip, (ip_table + i)->network + j);
if (!strcmp(ip_addr, host))
return true;
if (!j)
break;
}
while (j--);
}
return false;
}
DESC_MANAGER::DESC_MANAGER() : m_bDestroyed(false)
{
Initialize();
//NOTE : Destroy 끝에서 Initialize 를 부르는건 또 무슨 짓이냐..-_-; 정말
m_pPackageCrypt = new CClientPackageCryptInfo;
}
DESC_MANAGER::~DESC_MANAGER()
{
Destroy();
delete m_pPackageCrypt;
}
void DESC_MANAGER::Initialize()
{
m_iSocketsConnected = 0;
m_iHandleCount = 0;
m_iLocalUserCount = 0;
memset(m_aiEmpireUserCount, 0, sizeof(m_aiEmpireUserCount));
m_bDisconnectInvalidCRC = false;
}
void DESC_MANAGER::Destroy()
{
if (m_bDestroyed) {
return;
}
m_bDestroyed = true;
DESC_SET::iterator i = m_set_pkDesc.begin();
while (i != m_set_pkDesc.end())
{
LPDESC d = *i;
DESC_SET::iterator ci = i;
++i;
if (d->GetType() == DESC_TYPE_CONNECTOR)
continue;
if (d->IsPhase(PHASE_P2P))
continue;
DestroyDesc(d, false);
m_set_pkDesc.erase(ci);
}
i = m_set_pkDesc.begin();
while (i != m_set_pkDesc.end())
{
LPDESC d = *i;
DESC_SET::iterator ci = i;
++i;
DestroyDesc(d, false);
m_set_pkDesc.erase(ci);
}
m_set_pkClientDesc.clear();
//m_AccountIDMap.clear();
m_map_loginName.clear();
m_map_handle.clear();
Initialize();
}
DWORD DESC_MANAGER::CreateHandshake()
{
char crc_buf[8];
crc_t crc;
DESC_HANDSHAKE_MAP::iterator it;
RETRY:
do
{
DWORD val = thecore_random() % (1024 * 1024);
*(DWORD *) (crc_buf ) = val;
*((DWORD *) crc_buf + 1) = get_global_time();
crc = GetCRC32(crc_buf, 8);
it = m_map_handshake.find(crc);
}
while (it != m_map_handshake.end());
if (crc == 0)
goto RETRY;
return (crc);
}
LPDESC DESC_MANAGER::AcceptDesc(evconnlistener* listener, evutil_socket_t fd, sockaddr* address)
{
if (!IsValidIP(admin_ip, GetSocketHost(address).c_str())) // admin_ip 에 등록된 IP 는 최대 사용자 수에 구애받지 않는다.
{
if (m_iSocketsConnected >= MAX_ALLOW_USER)
{
sys_err("max connection reached. MAX_ALLOW_USER = %d", MAX_ALLOW_USER);
return nullptr;
}
}
event_base *base = evconnlistener_get_base(listener);
// Create the peer
LPDESC newd = new DESC;
crc_t handshake = CreateHandshake();
if(!newd->Setup(base, fd, address, ++m_iHandleCount, handshake)) {
delete newd;
return nullptr;
}
m_map_handshake.insert(DESC_HANDSHAKE_MAP::value_type(handshake, newd));
m_map_handle.insert(DESC_HANDLE_MAP::value_type(newd->GetHandle(), newd));
m_set_pkDesc.insert(newd);
++m_iSocketsConnected;
return (newd);
}
LPDESC DESC_MANAGER::AcceptP2PDesc(evconnlistener* listener, evutil_socket_t fd, sockaddr* address)
{
event_base *base = evconnlistener_get_base(listener);
LPDESC_P2P pkDesc = new DESC_P2P;
if (!pkDesc->Setup(base, fd, address))
{
sys_err("DESC_MANAGER::AcceptP2PDesc : Setup failed");
delete pkDesc;
return nullptr;
}
m_set_pkDesc.insert(pkDesc);
++m_iSocketsConnected;
sys_log(0, "DESC_MANAGER::AcceptP2PDesc %s:%u", GetSocketHost(address).c_str(), GetSocketPort(address));
P2P_MANAGER::instance().RegisterAcceptor(pkDesc);
return (pkDesc);
}
void DESC_MANAGER::ConnectAccount(const std::string& login, LPDESC d)
{
dev_log(LOG_DEB0, "BBBB ConnectAccount(%s)", login.c_str());
m_map_loginName.insert(DESC_LOGINNAME_MAP::value_type(login,d));
}
void DESC_MANAGER::DisconnectAccount(const std::string& login)
{
dev_log(LOG_DEB0, "BBBB DisConnectAccount(%s)", login.c_str());
m_map_loginName.erase(login);
}
void DESC_MANAGER::DestroyDesc(LPDESC d, bool bEraseFromSet)
{
if (bEraseFromSet)
m_set_pkDesc.erase(d);
if (d->GetHandshake())
m_map_handshake.erase(d->GetHandshake());
if (d->GetHandle() != 0)
m_map_handle.erase(d->GetHandle());
else
m_set_pkClientDesc.erase((LPCLIENT_DESC) d);
// Explicit call to the virtual function Destroy()
d->Destroy();
M2_DELETE(d);
--m_iSocketsConnected;
}
void DESC_MANAGER::DestroyClosed()
{
DESC_SET::iterator i = m_set_pkDesc.begin();
while (i != m_set_pkDesc.end())
{
LPDESC d = *i;
DESC_SET::iterator ci = i;
++i;
if (d->IsPhase(PHASE_CLOSE))
{
if (d->GetType() == DESC_TYPE_CONNECTOR)
{
LPCLIENT_DESC client_desc = (LPCLIENT_DESC)d;
if (client_desc->IsRetryWhenClosed())
{
client_desc->Reset();
continue;
}
}
DestroyDesc(d, false);
m_set_pkDesc.erase(ci);
}
}
}
LPDESC DESC_MANAGER::FindByLoginName(const std::string& login)
{
DESC_LOGINNAME_MAP::iterator it = m_map_loginName.find(login);
if (m_map_loginName.end() == it)
return NULL;
return (it->second);
}
LPDESC DESC_MANAGER::FindByHandle(DWORD handle)
{
DESC_HANDLE_MAP::iterator it = m_map_handle.find(handle);
if (m_map_handle.end() == it)
return NULL;
return (it->second);
}
const DESC_MANAGER::DESC_SET & DESC_MANAGER::GetClientSet()
{
return m_set_pkDesc;
}
struct name_with_desc_func
{
const char * m_name;
name_with_desc_func(const char * name) : m_name(name)
{
}
bool operator () (LPDESC d)
{
if (d->GetCharacter() && !strcmp(d->GetCharacter()->GetName(), m_name))
return true;
return false;
}
};
LPDESC DESC_MANAGER::FindByCharacterName(const char *name)
{
DESC_SET::iterator it = std::find_if (m_set_pkDesc.begin(), m_set_pkDesc.end(), name_with_desc_func(name));
return (it == m_set_pkDesc.end()) ? NULL : (*it);
}
LPCLIENT_DESC DESC_MANAGER::CreateConnectionDesc(event_base * base, evdns_base * dns_base, const char * host, WORD port, int iPhaseWhenSucceed, bool bRetryWhenClosed)
{
LPCLIENT_DESC newd = new CLIENT_DESC;
newd->Setup(base, dns_base, host, port);
newd->Connect(iPhaseWhenSucceed);
newd->SetRetryWhenClosed(bRetryWhenClosed);
m_set_pkDesc.insert(newd);
m_set_pkClientDesc.insert(newd);
++m_iSocketsConnected;
return (newd);
}
struct FuncTryConnect
{
void operator () (LPDESC d)
{
((LPCLIENT_DESC)d)->Connect();
}
};
void DESC_MANAGER::TryConnect()
{
FuncTryConnect f;
std::for_each(m_set_pkClientDesc.begin(), m_set_pkClientDesc.end(), f);
}
bool DESC_MANAGER::IsP2PDescExist(const char * szHost, WORD wPort)
{
CLIENT_DESC_SET::iterator it = m_set_pkClientDesc.begin();
while (it != m_set_pkClientDesc.end())
{
LPCLIENT_DESC d = *(it++);
if (!strcmp(d->GetHostName(), szHost) && d->GetP2PPort() == wPort)
return true;
}
return false;
}
LPDESC DESC_MANAGER::FindByHandshake(DWORD dwHandshake)
{
DESC_HANDSHAKE_MAP::iterator it = m_map_handshake.find(dwHandshake);
if (it == m_map_handshake.end())
return NULL;
return (it->second);
}
class FuncWho
{
public:
int iTotalCount;
int aiEmpireUserCount[EMPIRE_MAX_NUM];
FuncWho()
{
iTotalCount = 0;
memset(aiEmpireUserCount, 0, sizeof(aiEmpireUserCount));
}
void operator() (LPDESC d)
{
if (d->GetCharacter())
{
++iTotalCount;
++aiEmpireUserCount[d->GetEmpire()];
}
}
};
void DESC_MANAGER::UpdateLocalUserCount()
{
const DESC_SET & c_ref_set = GetClientSet();
FuncWho f;
f = std::for_each(c_ref_set.begin(), c_ref_set.end(), f);
m_iLocalUserCount = f.iTotalCount;
memcpy(m_aiEmpireUserCount, f.aiEmpireUserCount, sizeof(m_aiEmpireUserCount));
m_aiEmpireUserCount[1] += P2P_MANAGER::instance().GetEmpireUserCount(1);
m_aiEmpireUserCount[2] += P2P_MANAGER::instance().GetEmpireUserCount(2);
m_aiEmpireUserCount[3] += P2P_MANAGER::instance().GetEmpireUserCount(3);
}
void DESC_MANAGER::GetUserCount(int & iTotal, int ** paiEmpireUserCount, int & iLocalCount)
{
*paiEmpireUserCount = &m_aiEmpireUserCount[0];
int iCount = P2P_MANAGER::instance().GetCount();
if (iCount < 0)
{
sys_err("P2P_MANAGER::instance().GetCount() == -1");
}
iTotal = m_iLocalUserCount + iCount;
iLocalCount = m_iLocalUserCount;
}
DWORD DESC_MANAGER::MakeRandomKey(DWORD dwHandle)
{
DWORD random_key = thecore_random();
m_map_handle_random_key.insert(std::make_pair(dwHandle, random_key));
return random_key;
}
bool DESC_MANAGER::GetRandomKey(DWORD dwHandle, DWORD* prandom_key)
{
DESC_HANDLE_RANDOM_KEY_MAP::iterator it = m_map_handle_random_key.find(dwHandle);
if (it == m_map_handle_random_key.end())
return false;
*prandom_key = it->second;
return true;
}
LPDESC DESC_MANAGER::FindByLoginKey(DWORD dwKey)
{
std::map<DWORD, CLoginKey *>::iterator it = m_map_pkLoginKey.find(dwKey);
if (it == m_map_pkLoginKey.end())
return NULL;
return it->second->m_pkDesc;
}
DWORD DESC_MANAGER::CreateLoginKey(LPDESC d)
{
DWORD dwKey = 0;
do
{
dwKey = number(1, INT_MAX);
if (m_map_pkLoginKey.find(dwKey) != m_map_pkLoginKey.end())
continue;
CLoginKey * pkKey = M2_NEW CLoginKey(dwKey, d);
d->SetLoginKey(pkKey);
m_map_pkLoginKey.insert(std::make_pair(dwKey, pkKey));
break;
} while (1);
return dwKey;
}
void DESC_MANAGER::ProcessExpiredLoginKey()
{
DWORD dwCurrentTime = get_dword_time();
std::map<DWORD, CLoginKey *>::iterator it, it2;
it = m_map_pkLoginKey.begin();
while (it != m_map_pkLoginKey.end())
{
it2 = it++;
if (it2->second->m_dwExpireTime == 0)
continue;
if (dwCurrentTime - it2->second->m_dwExpireTime > 60000)
{
M2_DELETE(it2->second);
m_map_pkLoginKey.erase(it2);
}
}
}
bool DESC_MANAGER::LoadClientPackageCryptInfo(const char* pDirName)
{
return m_pPackageCrypt->LoadPackageCryptInfo(pDirName);
}
#ifdef __FreeBSD__
void DESC_MANAGER::NotifyClientPackageFileChanged( const std::string& dirName, eFileUpdatedOptions eUpdateOption )
{
Instance().LoadClientPackageCryptInfo(dirName.c_str());
}
#endif
void DESC_MANAGER::SendClientPackageCryptKey( LPDESC desc )
{
if( !desc )
{
return;
}
TPacketGCHybridCryptKeys packet;
{
packet.bHeader = HEADER_GC_HYBRIDCRYPT_KEYS;
m_pPackageCrypt->GetPackageCryptKeys( &(packet.pDataKeyStream), packet.KeyStreamLen );
}
if( packet.KeyStreamLen > 0 )
{
desc->Packet( packet.GetStreamData(), packet.GetStreamSize() );
}
}
void DESC_MANAGER::SendClientPackageSDBToLoadMap( LPDESC desc, const char* pMapName )
{
if( !desc )
{
return;
}
TPacketGCPackageSDB packet;
{
packet.bHeader = HEADER_GC_HYBRIDCRYPT_SDB;
if( !m_pPackageCrypt->GetRelatedMapSDBStreams( pMapName, &(packet.m_pDataSDBStream), packet.iStreamLen ) )
return;
}
if( packet.iStreamLen > 0 )
{
desc->Packet( packet.GetStreamData(), packet.GetStreamSize());
}
}