#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(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(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ÃÊ 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()); // ÆÄƼ¸¦ ó¸®ÇÒ ¼ö ÀÖ°Ô µÊ. 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ºÐ¸¶´Ù }; 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; }