#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( event->info ); if ( info == NULL ) { sys_err( "ping_event> 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(); 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) // ²÷´Â »óÅÂ¸é º¸³»Áö ¾Ê´Â´Ù. return; if (m_stRelayName.length() != 0) { // Relay ÆÐŶÀº ¾ÏȣȭÇÏÁö ¾Ê´Â´Ù. 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: // ¸Þ½ÅÀú°¡ ij¸¯ÅÍ´ÜÀ§°¡ µÇ¸é¼­ »èÁ¦ //MessengerManager::instance().Logout(GetAccountTable().login); m_pInputProcessor = &m_inputClose; break; case PHASE_HANDSHAKE: m_pInputProcessor = &m_inputHandshake; break; case PHASE_SELECT: // ¸Þ½ÅÀú°¡ ij¸¯ÅÍ´ÜÀ§°¡ µÇ¸é¼­ »èÁ¦ //MessengerManager::instance().Logout(GetAccountTable().login); // ÀǵµÀûÀ¸·Î break ¾È°Ë 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( event->info ); if ( info == NULL ) { sys_err( "disconnect_event> 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(); 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("´Ù¸¥ ÄÄÇ»ÅÍ¿¡¼­ ·Î±×ÀÎ ÇÏ¿© Á¢¼ÓÀ» Á¾·á ÇÕ´Ï´Ù.")); 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()); }