server/game/src/desc.cpp

826 lines
17 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.h"
#include "desc_client.h"
#include "desc_manager.h"
#include "char.h"
#include "protocol.h"
#include "packet.h"
#include "messenger_manager.h"
#include "sectree_manager.h"
#include "p2p.h"
#include "buffer_manager.h"
#include "sequence.h"
#include "guild.h"
#include "guild_manager.h"
#include "TrafficProfiler.h"
#include "locale_service.h"
#include "log.h"
extern int max_bytes_written;
extern int current_bytes_written;
extern int total_bytes_written;
void DescReadHandler(bufferevent *bev, void *ctx) {
auto* d = (LPDESC) ctx;
if (db_clientdesc == d)
{
int size = d->ProcessInput();
if (size)
sys_log(1, "DB_BYTES_READ: %d", size);
if (size < 0)
{
d->SetPhase(PHASE_CLOSE);
}
}
else if (!d->ProcessInput())
{
d->SetPhase(PHASE_CLOSE);
}
}
void DescWriteHandler(bufferevent *bev, void *ctx) {
auto* d = (LPDESC) ctx;
if (db_clientdesc == d)
{
evbuffer *output = bufferevent_get_output(bev);
size_t buf_size = evbuffer_get_length(output);
if (buf_size)
sys_log(1, "DB_BYTES_WRITE: size %d", buf_size);
}
else if (g_TeenDesc==d)
{
evbuffer *output = bufferevent_get_output(bev);
size_t buf_size = evbuffer_get_length(output);
if (buf_size)
sys_log(0, "TEEN::Send(size %d)", buf_size);
}
}
void DescEventHandler(bufferevent *bev, short events, void *ctx) {
auto* d = (LPDESC) ctx;
if (events & BEV_EVENT_ERROR)
sys_err("DESC libevent error, handle: %d", d->GetHandle());
if (events & BEV_EVENT_EOF)
sys_log(0, "DESC disconnected: handle %d", d->GetHandle());
// Either the socket was closed or an error occured, therefore we can disconnect this peer.
if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR))
d->SetPhase(PHASE_CLOSE);
}
DESC::DESC()
{
Initialize();
}
DESC::~DESC()
{
}
void DESC::Initialize()
{
m_bDestroyed = false;
m_pInputProcessor = NULL;
m_evbase = nullptr;
m_bufevent = nullptr;
m_iPhase = PHASE_CLOSE;
m_dwHandle = 0;
m_wPort = 0;
m_LastTryToConnectTime = 0;
m_dwHandshake = 0;
m_dwHandshakeSentTime = 0;
m_iHandshakeRetry = 0;
m_dwClientTime = 0;
m_bHandshaking = false;
m_pkPingEvent = NULL;
m_lpCharacter = NULL;
memset( &m_accountTable, 0, sizeof(m_accountTable) );
m_pLogFile = NULL;
m_wP2PPort = 0;
m_bP2PChannel = 0;
m_bAdminMode = false;
m_bPong = true;
m_bChannelStatusRequested = false;
m_iCurrentSequence = 0;
m_dwMatrixRows = m_dwMatrixCols = 0;
m_bMatrixTryCount = 0;
m_pkLoginKey = NULL;
m_dwLoginKey = 0;
m_dwPanamaKey = 0;
m_bCRCMagicCubeIdx = 0;
m_dwProcCRC = 0;
m_dwFileCRC = 0;
m_dwBillingExpireSecond = 0;
m_outtime = 0;
m_playtime = 0;
m_offtime = 0;
m_pkDisconnectEvent = NULL;
m_seq_vector.clear();
}
void DESC::Destroy()
{
if (m_bDestroyed) {
return;
}
m_bDestroyed = true;
if (m_pkLoginKey)
m_pkLoginKey->Expire();
if (GetAccountTable().id)
DESC_MANAGER::instance().DisconnectAccount(GetAccountTable().login);
if (m_pLogFile)
{
fclose(m_pLogFile);
m_pLogFile = NULL;
}
if (m_lpCharacter)
{
m_lpCharacter->Disconnect("DESC::~DESC");
m_lpCharacter = NULL;
}
event_cancel(&m_pkPingEvent);
event_cancel(&m_pkDisconnectEvent);
if (!g_bAuthServer)
{
if (m_accountTable.login[0] && m_accountTable.passwd[0])
{
TLogoutPacket pack;
strncpy(pack.login, m_accountTable.login, sizeof(pack.login));
strncpy(pack.passwd, m_accountTable.passwd, sizeof(pack.passwd));
db_clientdesc->DBPacket(HEADER_GD_LOGOUT, m_dwHandle, &pack, sizeof(TLogoutPacket));
}
}
if (m_bufevent != nullptr)
{
sys_log(0, "SYSTEM: closing socket.");
Log("SYSTEM: closing socket.");
bufferevent_free(m_bufevent);
m_bufevent = nullptr;
}
m_seq_vector.clear();
}
EVENTFUNC(ping_event)
{
DESC::desc_event_info* info = dynamic_cast<DESC::desc_event_info*>( event->info );
if ( info == NULL )
{
sys_err( "ping_event> <Factor> Null pointer" );
return 0;
}
LPDESC desc = info->desc;
if (desc->IsAdminMode())
return (ping_event_second_cycle);
if (!desc->IsPong())
{
sys_log(0, "PING_EVENT: no pong %s", desc->GetHostName());
desc->SetPhase(PHASE_CLOSE);
return (ping_event_second_cycle);
}
else
{
TPacketGCPing p;
p.header = HEADER_GC_PING;
desc->Packet(&p, sizeof(struct packet_ping));
desc->SetPong(false);
}
desc->SendHandshake(get_dword_time(), 0);
return (ping_event_second_cycle);
}
bool DESC::IsPong()
{
return m_bPong;
}
void DESC::SetPong(bool b)
{
m_bPong = b;
}
bool DESC::Setup(event_base * evbase, evutil_socket_t fd, const sockaddr * c_rSockAddr, DWORD _handle, DWORD _handshake)
{
m_bufevent = bufferevent_socket_new(evbase, fd, BEV_OPT_CLOSE_ON_FREE);
if (m_bufevent == nullptr) {
sys_err("DESC::Setup : Could not set up bufferevent!");
return false;
}
// Set the event handlers for this peer
bufferevent_setcb(m_bufevent, DescReadHandler, DescWriteHandler, DescEventHandler, this);
// Enable the events
bufferevent_enable(m_bufevent, EV_READ|EV_WRITE);
m_stHost = GetSocketHost(c_rSockAddr);
m_wPort = GetSocketPort(c_rSockAddr);
m_dwHandle = _handle;
// Ping Event
desc_event_info* info = AllocEventInfo<desc_event_info>();
info->desc = this;
assert(m_pkPingEvent == NULL);
m_pkPingEvent = event_create(ping_event, info, ping_event_second_cycle);
// Set Phase to handshake
SetPhase(PHASE_HANDSHAKE);
StartHandshake(_handshake);
sys_log(0, "SYSTEM: new connection from [%s] handshake %u, ptr %p",
m_stHost.c_str(), m_dwHandshake, this);
Log("SYSTEM: new connection from [%s] handshake %u ptr %p", m_stHost.c_str(), m_dwHandshake, this);
return true;
}
bool DESC::ProcessInput()
{
evbuffer *input = bufferevent_get_input(m_bufevent);
if (input == nullptr) {
sys_err("DESC::ProcessInput : nil input buffer");
return false;
}
if (!m_pInputProcessor) {
sys_err("no input processor");
return false;
}
// If CInputProcessor::Process returns false, then we switched to another phase, and we can continue reading
bool doContinue = true;
do {
size_t bytes_read = evbuffer_get_length(input);
// No data to read, we can continue
if (bytes_read == 0)
return true;
// Get the received data
void * data = evbuffer_pullup(input, bytes_read);
int iBytesProceed = 0; // The number of bytes that have been processed
doContinue = m_pInputProcessor->Process(this, data, bytes_read, iBytesProceed);
// Flush the read bytes from the network buffer
evbuffer_drain(input, iBytesProceed);
iBytesProceed = 0;
} while(!doContinue);
return true;
}
bool DESC::RawPacket(const void * c_pvData, int iSize)
{
if (m_iPhase == PHASE_CLOSE)
return false;
if (!m_bufevent) {
sys_err("Bufferevent not ready!");
return false;
}
if (bufferevent_write(m_bufevent, c_pvData, iSize) != 0) {
sys_err("Buffer write error!");
return false;
}
return true;
}
void DESC::Packet(const void * c_pvData, int iSize)
{
assert(iSize > 0);
if (m_iPhase == PHASE_CLOSE) // <20><><EFBFBD><EFBFBD> <20><><EFBFBD>¸<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʴ´<CAB4>.
return;
if (m_stRelayName.length() != 0)
{
// Relay <20><>Ŷ<EFBFBD><C5B6> <20><>ȣȭ<C8A3><C8AD><EFBFBD><EFBFBD> <20>ʴ´<CAB4>.
TPacketGGRelay p;
p.bHeader = HEADER_GG_RELAY;
strncpy(p.szName, m_stRelayName.c_str(), sizeof(p.szName));
p.lSize = iSize;
if (!RawPacket(&p, sizeof(p)))
{
m_iPhase = PHASE_CLOSE;
return;
}
m_stRelayName.clear();
if (!RawPacket(c_pvData, iSize))
{
m_iPhase = PHASE_CLOSE;
return;
}
}
else
{
// TRAFFIC_PROFILE
if (g_bTrafficProfileOn)
TrafficProfiler::instance().Report(TrafficProfiler::IODIR_OUTPUT, *(BYTE *) c_pvData, iSize);
// END_OF_TRAFFIC_PROFILER
if (!RawPacket(c_pvData, iSize)) {
m_iPhase = PHASE_CLOSE;
}
}
//sys_log(0, "%d bytes written (first byte %d)", iSize, *(BYTE *) c_pvData);
}
void DESC::SetPhase(int _phase)
{
m_iPhase = _phase;
TPacketGCPhase pack;
pack.header = HEADER_GC_PHASE;
pack.phase = _phase;
Packet(&pack, sizeof(TPacketGCPhase));
switch (m_iPhase)
{
case PHASE_CLOSE:
// <20>޽<EFBFBD><DEBD><EFBFBD><EFBFBD><EFBFBD> ij<><C4B3><EFBFBD>ʹ<EFBFBD><CDB4><EFBFBD><EFBFBD><EFBFBD> <20>Ǹ鼭 <20><><EFBFBD><EFBFBD>
//MessengerManager::instance().Logout(GetAccountTable().login);
m_pInputProcessor = &m_inputClose;
break;
case PHASE_HANDSHAKE:
m_pInputProcessor = &m_inputHandshake;
break;
case PHASE_SELECT:
// <20>޽<EFBFBD><DEBD><EFBFBD><EFBFBD><EFBFBD> ij<><C4B3><EFBFBD>ʹ<EFBFBD><CDB4><EFBFBD><EFBFBD><EFBFBD> <20>Ǹ鼭 <20><><EFBFBD><EFBFBD>
//MessengerManager::instance().Logout(GetAccountTable().login); // <20>ǵ<EFBFBD><C7B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> break <20>Ȱ<EFBFBD>
case PHASE_LOGIN:
case PHASE_LOADING:
m_pInputProcessor = &m_inputLogin;
break;
case PHASE_GAME:
case PHASE_DEAD:
m_pInputProcessor = &m_inputMain;
break;
case PHASE_AUTH:
m_pInputProcessor = &m_inputAuth;
sys_log(0, "AUTH_PHASE %p", this);
break;
}
}
void DESC::BindAccountTable(TAccountTable * pAccountTable)
{
assert(pAccountTable != NULL);
memcpy(&m_accountTable, pAccountTable, sizeof(TAccountTable));
DESC_MANAGER::instance().ConnectAccount(m_accountTable.login, this);
}
void DESC::Log(const char * format, ...)
{
if (!m_pLogFile)
return;
va_list args;
time_t ct = get_global_time();
struct tm tm = *localtime(&ct);
fprintf(m_pLogFile,
"%02d %02d %02d:%02d:%02d | ",
tm.tm_mon + 1,
tm.tm_mday,
tm.tm_hour,
tm.tm_min,
tm.tm_sec);
va_start(args, format);
vfprintf(m_pLogFile, format, args);
va_end(args);
fputs("\n", m_pLogFile);
fflush(m_pLogFile);
}
void DESC::StartHandshake(DWORD _handshake)
{
// Handshake
m_dwHandshake = _handshake;
SendHandshake(get_dword_time(), 0);
m_iHandshakeRetry = 0;
}
void DESC::SendHandshake(DWORD dwCurTime, LONG lNewDelta)
{
TPacketGCHandshake pack;
pack.bHeader = HEADER_GC_HANDSHAKE;
pack.dwHandshake = m_dwHandshake;
pack.dwTime = dwCurTime;
pack.lDelta = lNewDelta;
Packet(&pack, sizeof(TPacketGCHandshake));
m_dwHandshakeSentTime = dwCurTime;
m_bHandshaking = true;
}
bool DESC::HandshakeProcess(DWORD dwTime, LONG lDelta, bool bInfiniteRetry)
{
DWORD dwCurTime = get_dword_time();
if (lDelta < 0)
{
sys_err("Desc::HandshakeProcess : value error (lDelta %d, ip %s)", lDelta, m_stHost.c_str());
return false;
}
int bias = (int) (dwCurTime - (dwTime + lDelta));
if (bias >= 0 && bias <= 50)
{
if (bInfiniteRetry)
{
BYTE bHeader = HEADER_GC_TIME_SYNC;
Packet(&bHeader, sizeof(BYTE));
}
if (GetCharacter())
sys_log(0, "Handshake: client_time %u server_time %u name: %s", m_dwClientTime, dwCurTime, GetCharacter()->GetName());
else
sys_log(0, "Handshake: client_time %u server_time %u", m_dwClientTime, dwCurTime, lDelta);
m_dwClientTime = dwCurTime;
m_bHandshaking = false;
return true;
}
LONG lNewDelta = (LONG) (dwCurTime - dwTime) / 2;
if (lNewDelta < 0)
{
sys_log(0, "Handshake: lower than zero %d", lNewDelta);
lNewDelta = (dwCurTime - m_dwHandshakeSentTime) / 2;
}
sys_log(1, "Handshake: ServerTime %u dwTime %u lDelta %d SentTime %u lNewDelta %d", dwCurTime, dwTime, lDelta, m_dwHandshakeSentTime, lNewDelta);
if (!bInfiniteRetry)
if (++m_iHandshakeRetry > HANDSHAKE_RETRY_LIMIT)
{
sys_err("handshake retry limit reached! (limit %d character %s)",
HANDSHAKE_RETRY_LIMIT, GetCharacter() ? GetCharacter()->GetName() : "!NO CHARACTER!");
SetPhase(PHASE_CLOSE);
return false;
}
SendHandshake(dwCurTime, lNewDelta);
return false;
}
bool DESC::IsHandshaking()
{
return m_bHandshaking;
}
DWORD DESC::GetClientTime()
{
return m_dwClientTime;
}
void DESC::SetRelay(const char * c_pszName)
{
m_stRelayName = c_pszName;
}
void DESC::BindCharacter(LPCHARACTER ch)
{
m_lpCharacter = ch;
}
void DESC::FlushOutput()
{
if (m_bufevent == nullptr)
return;
if (bufferevent_flush(m_bufevent, EV_WRITE, BEV_FLUSH) < 0)
sys_log(0, "FLUSH FAIL");
else
sys_log(0, "FLUSH SUCCESS");
usleep(250000);
}
EVENTFUNC(disconnect_event)
{
DESC::desc_event_info* info = dynamic_cast<DESC::desc_event_info*>( event->info );
if ( info == NULL )
{
sys_err( "disconnect_event> <Factor> Null pointer" );
return 0;
}
LPDESC d = info->desc;
d->m_pkDisconnectEvent = NULL;
d->SetPhase(PHASE_CLOSE);
return 0;
}
bool DESC::DelayedDisconnect(int iSec)
{
if (m_pkDisconnectEvent != NULL) {
return false;
}
desc_event_info* info = AllocEventInfo<desc_event_info>();
info->desc = this;
m_pkDisconnectEvent = event_create(disconnect_event, info, PASSES_PER_SEC(iSec));
return true;
}
void DESC::DisconnectOfSameLogin()
{
if (GetCharacter())
{
if (m_pkDisconnectEvent)
return;
GetCharacter()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<EFBFBD>ٸ<EFBFBD> <20><>ǻ<EFBFBD>Ϳ<EFBFBD><CDBF><EFBFBD> <20>α<EFBFBD><CEB1><EFBFBD> <20>Ͽ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>մϴ<D5B4>."));
DelayedDisconnect(5);
}
else
{
SetPhase(PHASE_CLOSE);
}
}
void DESC::SetAdminMode()
{
m_bAdminMode = true;
}
bool DESC::IsAdminMode()
{
return m_bAdminMode;
}
BYTE DESC::GetSequence()
{
return gc_abSequence[m_iCurrentSequence];
}
void DESC::SetNextSequence()
{
if (++m_iCurrentSequence == SEQUENCE_MAX_NUM)
m_iCurrentSequence = 0;
}
void DESC::SendLoginSuccessPacket()
{
TAccountTable & rTable = GetAccountTable();
TPacketGCLoginSuccess p;
p.bHeader = HEADER_GC_LOGIN_SUCCESS_NEWSLOT;
p.handle = GetHandle();
p.random_key = DESC_MANAGER::instance().MakeRandomKey(GetHandle()); // FOR MARK
memcpy(p.players, rTable.players, sizeof(rTable.players));
for (int i = 0; i < PLAYER_PER_ACCOUNT; ++i)
{
CGuild* g = CGuildManager::instance().GetLinkedGuild(rTable.players[i].dwID);
if (g)
{
p.guild_id[i] = g->GetID();
strncpy(p.guild_name[i], g->GetName(), sizeof(p.guild_name[i]));
}
else
{
p.guild_id[i] = 0;
p.guild_name[i][0] = '\0';
}
}
Packet(&p, sizeof(TPacketGCLoginSuccess));
}
//void DESC::SendServerStatePacket(int nIndex)
//{
// TPacketGCStateCheck rp;
//
// int iTotal;
// int * paiEmpireUserCount;
// int iLocal;
//
// DESC_MANAGER::instance().GetUserCount(iTotal, &paiEmpireUserCount, iLocal);
//
// rp.header = 1;
// rp.key = 0;
// rp.index = nIndex;
//
// if (g_bNoMoreClient) rp.state = 0;
// else rp.state = iTotal > g_iFullUserCount ? 3 : iTotal > g_iBusyUserCount ? 2 : 1;
//
// this->Packet(&rp, sizeof(rp));
// //printf("STATE_CHECK PACKET PROCESSED.\n");
//}
void DESC::SetMatrixCardRowsAndColumns(unsigned int rows, unsigned int cols)
{
m_dwMatrixRows = rows;
m_dwMatrixCols = cols;
}
unsigned int DESC::GetMatrixRows()
{
return m_dwMatrixRows;
}
unsigned int DESC::GetMatrixCols()
{
return m_dwMatrixCols;
}
bool DESC::CheckMatrixTryCount()
{
if (++m_bMatrixTryCount >= 3)
return false;
return true;
}
void DESC::SetLoginKey(DWORD dwKey)
{
m_dwLoginKey = dwKey;
}
void DESC::SetLoginKey(CLoginKey * pkKey)
{
m_pkLoginKey = pkKey;
sys_log(0, "SetLoginKey %u", m_pkLoginKey->m_dwKey);
}
DWORD DESC::GetLoginKey()
{
if (m_pkLoginKey)
return m_pkLoginKey->m_dwKey;
return m_dwLoginKey;
}
const BYTE* GetKey_20050304Myevan()
{
static bool bGenerated = false;
static DWORD s_adwKey[1938];
if (!bGenerated)
{
bGenerated = true;
DWORD seed = 1491971513;
for (UINT i = 0; i < BYTE(seed); ++i)
{
seed ^= 2148941891ul;
seed += 3592385981ul;
s_adwKey[i] = seed;
}
}
return (const BYTE*)s_adwKey;
}
void DESC::AssembleCRCMagicCube(BYTE bProcPiece, BYTE bFilePiece)
{
static BYTE abXORTable[32] =
{
102, 30, 0, 0, 0, 0, 0, 0,
188, 44, 0, 0, 0, 0, 0, 0,
39, 201, 0, 0, 0, 0, 0, 0,
43, 5, 0, 0, 0, 0, 0, 0,
};
bProcPiece = (bProcPiece ^ abXORTable[m_bCRCMagicCubeIdx]);
bFilePiece = (bFilePiece ^ abXORTable[m_bCRCMagicCubeIdx+1]);
m_dwProcCRC |= bProcPiece << m_bCRCMagicCubeIdx;
m_dwFileCRC |= bFilePiece << m_bCRCMagicCubeIdx;
m_bCRCMagicCubeIdx += 8;
if (!(m_bCRCMagicCubeIdx & 31))
{
m_dwProcCRC = 0;
m_dwFileCRC = 0;
m_bCRCMagicCubeIdx = 0;
}
}
void DESC::SetBillingExpireSecond(DWORD dwSec)
{
m_dwBillingExpireSecond = dwSec;
}
DWORD DESC::GetBillingExpireSecond()
{
return m_dwBillingExpireSecond;
}
void DESC::push_seq(BYTE hdr, BYTE seq)
{
if (m_seq_vector.size()>=20)
{
m_seq_vector.erase(m_seq_vector.begin());
}
seq_t info = { hdr, seq };
m_seq_vector.push_back(info);
}
BYTE DESC::GetEmpire()
{
return m_accountTable.bEmpire;
}
void DESC::ChatPacket(BYTE type, const char * format, ...)
{
char chatbuf[CHAT_MAX_LEN + 1];
va_list args;
va_start(args, format);
int len = vsnprintf(chatbuf, sizeof(chatbuf), format, args);
va_end(args);
struct packet_chat pack_chat;
pack_chat.header = HEADER_GC_CHAT;
pack_chat.size = sizeof(struct packet_chat) + len;
pack_chat.type = type;
pack_chat.id = 0;
pack_chat.bEmpire = GetEmpire();
TEMP_BUFFER buf;
buf.write(&pack_chat, sizeof(struct packet_chat));
buf.write(chatbuf, len);
Packet(buf.read_peek(), buf.size());
}