server/game/src/desc_client.cpp

337 lines
8.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "stdafx.h"
#include "config.h"
#include "utils.h"
#include "desc_client.h"
#include "desc_manager.h"
#include "char.h"
#include "protocol.h"
#include "p2p.h"
#include "buffer_manager.h"
#include "guild_manager.h"
#include "db.h"
#include "party.h"
LPCLIENT_DESC db_clientdesc = NULL;
LPCLIENT_DESC g_pkAuthMasterDesc = NULL;
LPCLIENT_DESC g_NetmarbleDBDesc = NULL;
LPCLIENT_DESC g_TeenDesc = NULL;
static const char* GetKnownClientDescName(LPCLIENT_DESC desc) {
if (desc == db_clientdesc) {
return "db_clientdesc";
} else if (desc == g_pkAuthMasterDesc) {
return "g_pkAuthMasterDesc";
} else if (desc == g_NetmarbleDBDesc) {
return "g_NetmarbleDBDesc";
} else if (desc == g_TeenDesc) {
return "g_TeenDesc";
}
return "unknown";
}
void ClientDescEventHandler(bufferevent *bev, short events, void *ptr) {
auto * clientDesc = static_cast<LPCLIENT_DESC>(ptr);
if (events & BEV_EVENT_CONNECTED) {
sys_log(0, "SYSTEM: connected to server (ptr %p)", clientDesc);
clientDesc->OnConnectSuccessful();
// Now that we're connected, we can set the read/write/event handlers (and therefore stop using this handler)
auto * desc = static_cast<LPDESC>(clientDesc);
bufferevent_setcb(bev, DescReadHandler, DescWriteHandler, DescEventHandler, desc);
} else if (events & (BEV_EVENT_ERROR|BEV_EVENT_EOF)) {
if (events & BEV_EVENT_ERROR) {
int err = bufferevent_socket_get_dns_error(bev);
if (err)
sys_err("SYSTEM: Client connection DNS error: %s", evutil_gai_strerror(err));
}
sys_log(0, "SYSTEM: closing client connection (ptr %p)", clientDesc);
clientDesc->SetPhase(PHASE_CLOSE);
}
}
CLIENT_DESC::CLIENT_DESC()
{
m_iPhaseWhenSucceed = 0;
m_bRetryWhenClosed = false;
m_LastTryToConnectTime = 0;
m_tLastChannelStatusUpdateTime = 0;
}
CLIENT_DESC::~CLIENT_DESC()
{
}
void CLIENT_DESC::Destroy()
{
if (m_bufevent == nullptr)
return;
P2P_MANAGER::instance().UnregisterConnector(this);
if (this == db_clientdesc)
{
CPartyManager::instance().DeleteAllParty();
CPartyManager::instance().DisablePCParty();
CGuildManager::instance().StopAllGuildWar();
DBManager::instance().StopAllBilling();
}
sys_log(0, "SYSTEM: closing client socket.");
bufferevent_free(m_bufevent);
m_bufevent = nullptr;
// Chain up to base class Destroy()
DESC::Destroy();
}
void CLIENT_DESC::SetRetryWhenClosed(bool b)
{
m_bRetryWhenClosed = b;
}
bool CLIENT_DESC::Connect(int iPhaseWhenSucceed)
{
if (iPhaseWhenSucceed != 0)
m_iPhaseWhenSucceed = iPhaseWhenSucceed;
if (get_global_time() - m_LastTryToConnectTime < 3) // 3<><33>
return false;
m_LastTryToConnectTime = get_global_time();
if (m_bufevent != nullptr)
return false;
sys_log(0, "SYSTEM: Trying to connect to %s:%d", m_stHost.c_str(), m_wPort);
if (m_evbase == nullptr) {
sys_err("SYSTEM: event base not set!");
return false;
}
if (m_dnsBase == nullptr) {
sys_err("SYSTEM: DNS event base not set!");
return false;
}
m_bufevent = bufferevent_socket_new(m_evbase, -1, BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(m_bufevent, NULL, NULL, ClientDescEventHandler, this);
bufferevent_enable(m_bufevent, EV_READ|EV_WRITE);
bufferevent_socket_connect_hostname(m_bufevent, m_dnsBase, AF_UNSPEC, m_stHost.c_str(), m_wPort);
SetPhase(PHASE_CLIENT_CONNECTING);
return true;
}
void CLIENT_DESC::OnConnectSuccessful() {
sys_log(0, "SYSTEM: connected to server (ptr %p)", this);
SetPhase(m_iPhaseWhenSucceed);
}
void CLIENT_DESC::Setup(event_base* base, evdns_base * dns_base, const char * _host, WORD _port)
{
m_evbase = base;
m_dnsBase = dns_base;
m_stHost = _host;
m_wPort = _port;
m_bufevent = nullptr;
}
void CLIENT_DESC::SetPhase(int iPhase)
{
switch (iPhase)
{
case PHASE_CLIENT_CONNECTING:
sys_log(1, "PHASE_CLIENT_DESC::CONNECTING");
m_pInputProcessor = NULL;
break;
case PHASE_DBCLIENT:
{
sys_log(1, "PHASE_DBCLIENT");
if (!g_bAuthServer)
{
static bool bSentBoot = false;
if (!bSentBoot)
{
bSentBoot = true;
TPacketGDBoot p;
p.dwItemIDRange[0] = 0;
p.dwItemIDRange[1] = 0;
memcpy(p.szIP, g_szPublicIP, 16);
DBPacket(HEADER_GD_BOOT, 0, &p, sizeof(p));
}
}
TEMP_BUFFER buf;
TPacketGDSetup p;
memset(&p, 0, sizeof(p));
strncpy(p.szPublicIP, g_szPublicIP, sizeof(p.szPublicIP));
if (!g_bAuthServer)
{
p.bChannel = g_bChannel;
p.wListenPort = mother_port;
p.wP2PPort = p2p_port;
p.bAuthServer = false;
map_allow_copy(p.alMaps, 32);
const DESC_MANAGER::DESC_SET & c_set = DESC_MANAGER::instance().GetClientSet();
DESC_MANAGER::DESC_SET::const_iterator it;
for (it = c_set.begin(); it != c_set.end(); ++it)
{
LPDESC d = *it;
if (d->GetAccountTable().id != 0)
++p.dwLoginCount;
}
buf.write(&p, sizeof(p));
if (p.dwLoginCount)
{
TPacketLoginOnSetup pck;
for (it = c_set.begin(); it != c_set.end(); ++it)
{
LPDESC d = *it;
TAccountTable & r = d->GetAccountTable();
if (r.id != 0)
{
pck.dwID = r.id;
strncpy(pck.szLogin, r.login, sizeof(pck.szLogin));
strncpy(pck.szSocialID, r.social_id, sizeof(pck.szSocialID));
strncpy(pck.szHost, d->GetHostName(), sizeof(pck.szHost));
pck.dwLoginKey = d->GetLoginKey();
buf.write(&pck, sizeof(TPacketLoginOnSetup));
}
}
}
sys_log(0, "DB_SETUP current user %d size %d", p.dwLoginCount, buf.size());
// <20><>Ƽ<EFBFBD><C6BC> ó<><C3B3><EFBFBD><EFBFBD> <20><> <20>ְ<EFBFBD> <20><>.
CPartyManager::instance().EnablePCParty();
//CPartyManager::instance().SendPartyToDB();
}
else
{
p.bAuthServer = true;
buf.write(&p, sizeof(p));
}
DBPacket(HEADER_GD_SETUP, 0, buf.read_peek(), buf.size());
m_pInputProcessor = &m_inputDB;
}
break;
case PHASE_P2P:
sys_log(1, "PHASE_P2P");
m_pInputProcessor = &m_inputP2P;
break;
case PHASE_CLOSE:
m_pInputProcessor = NULL;
break;
case PHASE_TEEN:
m_inputTeen.SetStep(0);
m_pInputProcessor = &m_inputTeen;
break;
}
m_iPhase = iPhase;
}
void CLIENT_DESC::DBPacketHeader(BYTE bHeader, DWORD dwHandle, DWORD dwSize)
{
DESC::RawPacket(encode_byte(bHeader), sizeof(BYTE));
DESC::RawPacket(encode_4bytes(dwHandle), sizeof(DWORD));
DESC::RawPacket(encode_4bytes(dwSize), sizeof(DWORD));
}
void CLIENT_DESC::DBPacket(BYTE bHeader, DWORD dwHandle, const void * c_pvData, DWORD dwSize)
{
if (m_bufevent == nullptr) {
sys_log(0, "CLIENT_DESC [%s] trying DBPacket() while not connected",
GetKnownClientDescName(this));
return;
}
sys_log(1, "DB_PACKET: header %d handle %d size %d", bHeader, dwHandle, dwSize);
DBPacketHeader(bHeader, dwHandle, dwSize);
if (c_pvData)
DESC::RawPacket(c_pvData, dwSize);
}
void CLIENT_DESC::Packet(const void * c_pvData, int iSize)
{
if (m_bufevent == nullptr) {
sys_log(0, "CLIENT_DESC [%s] trying Packet() while not connected",
GetKnownClientDescName(this));
return;
}
DESC::RawPacket(c_pvData, iSize);
}
bool CLIENT_DESC::IsRetryWhenClosed()
{
return (0 == thecore_is_shutdowned() && m_bRetryWhenClosed);
}
void CLIENT_DESC::Update(DWORD t)
{
if (!g_bAuthServer) {
UpdateChannelStatus(t, false);
}
}
void CLIENT_DESC::UpdateChannelStatus(DWORD t, bool fForce)
{
enum {
CHANNELSTATUS_UPDATE_PERIOD = 5*60*1000, // 5<>и<EFBFBD><D0B8><EFBFBD>
};
if (fForce || m_tLastChannelStatusUpdateTime+CHANNELSTATUS_UPDATE_PERIOD < t) {
int iTotal;
int * paiEmpireUserCount;
int iLocal;
DESC_MANAGER::instance().GetUserCount(iTotal, &paiEmpireUserCount, iLocal);
TChannelStatus channelStatus;
channelStatus.nPort = mother_port;
if (g_bNoMoreClient) channelStatus.bStatus = 0;
else channelStatus.bStatus = iTotal > g_iFullUserCount ? 3 : iTotal > g_iBusyUserCount ? 2 : 1;
DBPacket(HEADER_GD_UPDATE_CHANNELSTATUS, 0, &channelStatus, sizeof(channelStatus));
m_tLastChannelStatusUpdateTime = t;
}
}
void CLIENT_DESC::Reset()
{
// Backup connection target info
event_base * evbase = m_evbase;
std::string host = m_stHost;
WORD port = m_wPort;
Destroy();
Initialize();
// Restore connection target info
m_evbase = evbase;
m_stHost = host;
m_wPort = port;
}