forked from metin2/server
1135 lines
24 KiB
C++
1135 lines
24 KiB
C++
#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 "HackShield.h"
|
||
#include "log.h"
|
||
|
||
extern int max_bytes_written;
|
||
extern int current_bytes_written;
|
||
extern int total_bytes_written;
|
||
|
||
DESC::DESC()
|
||
{
|
||
Initialize();
|
||
}
|
||
|
||
DESC::~DESC()
|
||
{
|
||
}
|
||
|
||
void DESC::Initialize()
|
||
{
|
||
m_bDestroyed = false;
|
||
|
||
m_pInputProcessor = NULL;
|
||
m_lpFdw = NULL;
|
||
m_sock = INVALID_SOCKET;
|
||
m_iPhase = PHASE_CLOSE;
|
||
m_dwHandle = 0;
|
||
|
||
m_wPort = 0;
|
||
m_LastTryToConnectTime = 0;
|
||
|
||
m_lpInputBuffer = NULL;
|
||
m_iMinInputBufferLen = 0;
|
||
|
||
m_dwHandshake = 0;
|
||
m_dwHandshakeSentTime = 0;
|
||
m_iHandshakeRetry = 0;
|
||
m_dwClientTime = 0;
|
||
m_bHandshaking = false;
|
||
|
||
m_lpBufferedOutputBuffer = NULL;
|
||
m_lpOutputBuffer = NULL;
|
||
|
||
m_pkPingEvent = NULL;
|
||
m_lpCharacter = NULL;
|
||
memset( &m_accountTable, 0, sizeof(m_accountTable) );
|
||
|
||
memset( &m_SockAddr, 0, sizeof(m_SockAddr) );
|
||
memset( &m_UDPSockAddr, 0, sizeof(m_UDPSockAddr) );
|
||
|
||
m_pLogFile = NULL;
|
||
|
||
#ifndef _IMPROVED_PACKET_ENCRYPTION_
|
||
m_bEncrypted = false;
|
||
#endif
|
||
|
||
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;
|
||
|
||
#ifndef _IMPROVED_PACKET_ENCRYPTION_
|
||
memset( m_adwDecryptionKey, 0, sizeof(m_adwDecryptionKey) );
|
||
memset( m_adwEncryptionKey, 0, sizeof(m_adwEncryptionKey) );
|
||
#endif
|
||
|
||
m_bCRCMagicCubeIdx = 0;
|
||
m_dwProcCRC = 0;
|
||
m_dwFileCRC = 0;
|
||
m_bHackCRCQuery = 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;
|
||
}
|
||
|
||
SAFE_BUFFER_DELETE(m_lpOutputBuffer);
|
||
SAFE_BUFFER_DELETE(m_lpInputBuffer);
|
||
|
||
event_cancel(&m_pkPingEvent);
|
||
event_cancel(&m_pkDisconnectEvent);
|
||
|
||
if (!g_bAuthServer)
|
||
{
|
||
if (m_accountTable.login[0] && m_accountTable.passwd[0])
|
||
{
|
||
TLogoutPacket pack;
|
||
|
||
strlcpy(pack.login, m_accountTable.login, sizeof(pack.login));
|
||
strlcpy(pack.passwd, m_accountTable.passwd, sizeof(pack.passwd));
|
||
|
||
db_clientdesc->DBPacket(HEADER_GD_LOGOUT, m_dwHandle, &pack, sizeof(TLogoutPacket));
|
||
}
|
||
}
|
||
|
||
if (m_sock != INVALID_SOCKET)
|
||
{
|
||
sys_log(0, "SYSTEM: closing socket. DESC #%d", m_sock);
|
||
Log("SYSTEM: closing socket. DESC #%d", m_sock);
|
||
fdwatch_del_fd(m_lpFdw, m_sock);
|
||
|
||
#ifdef _IMPROVED_PACKET_ENCRYPTION_
|
||
cipher_.CleanUp();
|
||
#endif
|
||
|
||
socket_close(m_sock);
|
||
m_sock = INVALID_SOCKET;
|
||
}
|
||
|
||
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);
|
||
}
|
||
|
||
#ifdef ENABLE_LIMIT_TIME
|
||
if ((unsigned)get_global_time() >= GLOBAL_LIMIT_TIME)
|
||
{
|
||
extern void ClearAdminPages();
|
||
ClearAdminPages();
|
||
extern g_bShutdown;
|
||
g_bShutdown = true;
|
||
}
|
||
#endif
|
||
|
||
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(LPFDWATCH _fdw, socket_t _fd, const struct sockaddr_in & c_rSockAddr, DWORD _handle, DWORD _handshake)
|
||
{
|
||
m_lpFdw = _fdw;
|
||
m_sock = _fd;
|
||
|
||
m_stHost = inet_ntoa(c_rSockAddr.sin_addr);
|
||
m_wPort = c_rSockAddr.sin_port;
|
||
m_dwHandle = _handle;
|
||
|
||
//if (LC_IsEurope() == true || LC_IsNewCIBN())
|
||
// m_lpOutputBuffer = buffer_new(DEFAULT_PACKET_BUFFER_SIZE * 2);
|
||
//else
|
||
//NOTE: <20>̰<EFBFBD> <20><><EFBFBD><EFBFBD> <20>ٸ<EFBFBD><D9B8><EFBFBD> <20><><EFBFBD>ƾ<EFBFBD><C6BE><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ֳ<EFBFBD>?
|
||
m_lpOutputBuffer = buffer_new(DEFAULT_PACKET_BUFFER_SIZE * 2);
|
||
|
||
m_iMinInputBufferLen = MAX_INPUT_LEN >> 1;
|
||
m_lpInputBuffer = buffer_new(MAX_INPUT_LEN);
|
||
|
||
m_SockAddr = c_rSockAddr;
|
||
|
||
fdwatch_add_fd(m_lpFdw, m_sock, this, FDW_READ, false);
|
||
|
||
// 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);
|
||
|
||
#ifndef _IMPROVED_PACKET_ENCRYPTION_
|
||
if (LC_IsEurope())
|
||
{
|
||
thecore_memcpy(m_adwEncryptionKey, "1234abcd5678efgh", sizeof(DWORD) * 4);
|
||
thecore_memcpy(m_adwDecryptionKey, "1234abcd5678efgh", sizeof(DWORD) * 4);
|
||
}
|
||
else
|
||
{
|
||
thecore_memcpy(m_adwEncryptionKey, "testtesttesttest", sizeof(DWORD) * 4);
|
||
thecore_memcpy(m_adwDecryptionKey, "testtesttesttest", sizeof(DWORD) * 4);
|
||
}
|
||
#endif // _IMPROVED_PACKET_ENCRYPTION_
|
||
|
||
// Set Phase to handshake
|
||
SetPhase(PHASE_HANDSHAKE);
|
||
StartHandshake(_handshake);
|
||
|
||
sys_log(0, "SYSTEM: new connection from [%s] fd: %d handshake %u output input_len %d, ptr %p",
|
||
m_stHost.c_str(), m_sock, m_dwHandshake, buffer_size(m_lpInputBuffer), this);
|
||
|
||
Log("SYSTEM: new connection from [%s] fd: %d handshake %u ptr %p", m_stHost.c_str(), m_sock, m_dwHandshake, this);
|
||
return true;
|
||
}
|
||
|
||
int DESC::ProcessInput()
|
||
{
|
||
ssize_t bytes_read;
|
||
|
||
if (!m_lpInputBuffer)
|
||
{
|
||
sys_err("DESC::ProcessInput : nil input buffer");
|
||
return -1;
|
||
}
|
||
|
||
buffer_adjust_size(m_lpInputBuffer, m_iMinInputBufferLen);
|
||
bytes_read = socket_read(m_sock, (char *) buffer_write_peek(m_lpInputBuffer), buffer_has_space(m_lpInputBuffer));
|
||
|
||
if (bytes_read < 0)
|
||
return -1;
|
||
else if (bytes_read == 0)
|
||
return 0;
|
||
|
||
buffer_write_proceed(m_lpInputBuffer, bytes_read);
|
||
|
||
if (!m_pInputProcessor)
|
||
sys_err("no input processor");
|
||
#ifdef _IMPROVED_PACKET_ENCRYPTION_
|
||
else
|
||
{
|
||
if (cipher_.activated()) {
|
||
cipher_.Decrypt(const_cast<void*>(buffer_read_peek(m_lpInputBuffer)), buffer_size(m_lpInputBuffer));
|
||
}
|
||
|
||
int iBytesProceed = 0;
|
||
|
||
// false<73><65> <20><><EFBFBD><EFBFBD> <20>Ǹ<EFBFBD> <20>ٸ<EFBFBD> phase<73><65> <20>ٲ<EFBFBD> <20><><EFBFBD>̹Ƿ<CCB9> <20>ٽ<EFBFBD> <20><><EFBFBD>μ<EFBFBD><CEBC><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>!
|
||
while (!m_pInputProcessor->Process(this, buffer_read_peek(m_lpInputBuffer), buffer_size(m_lpInputBuffer), iBytesProceed))
|
||
{
|
||
buffer_read_proceed(m_lpInputBuffer, iBytesProceed);
|
||
iBytesProceed = 0;
|
||
}
|
||
|
||
buffer_read_proceed(m_lpInputBuffer, iBytesProceed);
|
||
}
|
||
#else
|
||
else if (!m_bEncrypted)
|
||
{
|
||
int iBytesProceed = 0;
|
||
|
||
// false<73><65> <20><><EFBFBD><EFBFBD> <20>Ǹ<EFBFBD> <20>ٸ<EFBFBD> phase<73><65> <20>ٲ<EFBFBD> <20><><EFBFBD>̹Ƿ<CCB9> <20>ٽ<EFBFBD> <20><><EFBFBD>μ<EFBFBD><CEBC><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>!
|
||
while (!m_pInputProcessor->Process(this, buffer_read_peek(m_lpInputBuffer), buffer_size(m_lpInputBuffer), iBytesProceed))
|
||
{
|
||
buffer_read_proceed(m_lpInputBuffer, iBytesProceed);
|
||
iBytesProceed = 0;
|
||
}
|
||
|
||
buffer_read_proceed(m_lpInputBuffer, iBytesProceed);
|
||
}
|
||
else
|
||
{
|
||
int iSizeBuffer = buffer_size(m_lpInputBuffer);
|
||
|
||
// 8<><38><EFBFBD><EFBFBD>Ʈ <20><><EFBFBD><EFBFBD><EFBFBD>θ<EFBFBD> ó<><C3B3><EFBFBD>Ѵ<EFBFBD>. 8<><38><EFBFBD><EFBFBD>Ʈ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD> <20>߸<EFBFBD><DFB8><EFBFBD> <20><>ȣȭ <20><><EFBFBD>۸<EFBFBD> <20><>ȣȭ
|
||
// <20><> <20><><EFBFBD>ɼ<EFBFBD><C9BC><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD> ©<><C2A9><EFBFBD><EFBFBD> ó<><C3B3><EFBFBD>ϱ<EFBFBD><CFB1><EFBFBD> <20>Ѵ<EFBFBD>.
|
||
if (iSizeBuffer & 7) // & 7<><37> % 8<><38> <20><><EFBFBD><EFBFBD>. 2<><32> <20>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
iSizeBuffer -= iSizeBuffer & 7;
|
||
|
||
if (iSizeBuffer > 0)
|
||
{
|
||
TEMP_BUFFER tempbuf;
|
||
LPBUFFER lpBufferDecrypt = tempbuf.getptr();
|
||
buffer_adjust_size(lpBufferDecrypt, iSizeBuffer);
|
||
|
||
int iSizeAfter = TEA_Decrypt((DWORD *) buffer_write_peek(lpBufferDecrypt),
|
||
(DWORD *) buffer_read_peek(m_lpInputBuffer),
|
||
GetDecryptionKey(),
|
||
iSizeBuffer);
|
||
|
||
buffer_write_proceed(lpBufferDecrypt, iSizeAfter);
|
||
|
||
int iBytesProceed = 0;
|
||
|
||
// false<73><65> <20><><EFBFBD><EFBFBD> <20>Ǹ<EFBFBD> <20>ٸ<EFBFBD> phase<73><65> <20>ٲ<EFBFBD> <20><><EFBFBD>̹Ƿ<CCB9> <20>ٽ<EFBFBD> <20><><EFBFBD>μ<EFBFBD><CEBC><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>!
|
||
while (!m_pInputProcessor->Process(this, buffer_read_peek(lpBufferDecrypt), buffer_size(lpBufferDecrypt), iBytesProceed))
|
||
{
|
||
if (iBytesProceed > iSizeBuffer)
|
||
{
|
||
buffer_read_proceed(m_lpInputBuffer, iSizeBuffer);
|
||
iSizeBuffer = 0;
|
||
iBytesProceed = 0;
|
||
break;
|
||
}
|
||
|
||
buffer_read_proceed(m_lpInputBuffer, iBytesProceed);
|
||
iSizeBuffer -= iBytesProceed;
|
||
|
||
buffer_read_proceed(lpBufferDecrypt, iBytesProceed);
|
||
iBytesProceed = 0;
|
||
}
|
||
|
||
buffer_read_proceed(m_lpInputBuffer, iBytesProceed);
|
||
}
|
||
}
|
||
#endif // _IMPROVED_PACKET_ENCRYPTION_
|
||
|
||
return (bytes_read);
|
||
}
|
||
|
||
int DESC::ProcessOutput()
|
||
{
|
||
if (buffer_size(m_lpOutputBuffer) <= 0)
|
||
return 0;
|
||
|
||
int buffer_left = fdwatch_get_buffer_size(m_lpFdw, m_sock);
|
||
|
||
if (buffer_left <= 0)
|
||
return 0;
|
||
|
||
int bytes_to_write = MIN(buffer_left, buffer_size(m_lpOutputBuffer));
|
||
|
||
if (bytes_to_write == 0)
|
||
return 0;
|
||
|
||
int result = socket_write(m_sock, (const char *) buffer_read_peek(m_lpOutputBuffer), bytes_to_write);
|
||
|
||
if (result == 0)
|
||
{
|
||
//sys_log(0, "%d bytes written to %s first %u", bytes_to_write, GetHostName(), *(BYTE *) buffer_read_peek(m_lpOutputBuffer));
|
||
//Log("%d bytes written", bytes_to_write);
|
||
max_bytes_written = MAX(bytes_to_write, max_bytes_written);
|
||
|
||
total_bytes_written += bytes_to_write;
|
||
current_bytes_written += bytes_to_write;
|
||
|
||
buffer_read_proceed(m_lpOutputBuffer, bytes_to_write);
|
||
|
||
if (buffer_size(m_lpOutputBuffer) != 0)
|
||
fdwatch_add_fd(m_lpFdw, m_sock, this, FDW_WRITE, true);
|
||
}
|
||
|
||
return (result);
|
||
}
|
||
|
||
void DESC::BufferedPacket(const void * c_pvData, int iSize)
|
||
{
|
||
if (m_iPhase == PHASE_CLOSE)
|
||
return;
|
||
|
||
if (!m_lpBufferedOutputBuffer)
|
||
m_lpBufferedOutputBuffer = buffer_new(MAX(1024, iSize));
|
||
|
||
buffer_write(m_lpBufferedOutputBuffer, c_pvData, iSize);
|
||
}
|
||
|
||
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;
|
||
strlcpy(p.szName, m_stRelayName.c_str(), sizeof(p.szName));
|
||
p.lSize = iSize;
|
||
|
||
if (!packet_encode(m_lpOutputBuffer, &p, sizeof(p)))
|
||
{
|
||
m_iPhase = PHASE_CLOSE;
|
||
return;
|
||
}
|
||
|
||
m_stRelayName.clear();
|
||
|
||
if (!packet_encode(m_lpOutputBuffer, c_pvData, iSize))
|
||
{
|
||
m_iPhase = PHASE_CLOSE;
|
||
return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (m_lpBufferedOutputBuffer)
|
||
{
|
||
buffer_write(m_lpBufferedOutputBuffer, c_pvData, iSize);
|
||
|
||
c_pvData = buffer_read_peek(m_lpBufferedOutputBuffer);
|
||
iSize = buffer_size(m_lpBufferedOutputBuffer);
|
||
}
|
||
|
||
// TRAFFIC_PROFILE
|
||
if (g_bTrafficProfileOn)
|
||
TrafficProfiler::instance().Report(TrafficProfiler::IODIR_OUTPUT, *(BYTE *) c_pvData, iSize);
|
||
// END_OF_TRAFFIC_PROFILER
|
||
|
||
#ifdef _IMPROVED_PACKET_ENCRYPTION_
|
||
void* buf = buffer_write_peek(m_lpOutputBuffer);
|
||
|
||
|
||
if (packet_encode(m_lpOutputBuffer, c_pvData, iSize))
|
||
{
|
||
if (cipher_.activated()) {
|
||
cipher_.Encrypt(buf, iSize);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
m_iPhase = PHASE_CLOSE;
|
||
}
|
||
#else
|
||
if (!m_bEncrypted)
|
||
{
|
||
if (!packet_encode(m_lpOutputBuffer, c_pvData, iSize))
|
||
{
|
||
m_iPhase = PHASE_CLOSE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (buffer_has_space(m_lpOutputBuffer) < iSize + 8)
|
||
{
|
||
sys_err("desc buffer mem_size overflow. memsize(%u) write_pos(%u) iSize(%d)",
|
||
m_lpOutputBuffer->mem_size, m_lpOutputBuffer->write_point_pos, iSize);
|
||
|
||
m_iPhase = PHASE_CLOSE;
|
||
}
|
||
else
|
||
{
|
||
// <20><>ȣȭ<C8A3><C8AD> <20>ʿ<EFBFBD><CABF><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> ũ<>⸦ Ȯ<><C8AE><EFBFBD>Ѵ<EFBFBD>.
|
||
/* buffer_adjust_size(m_lpOutputBuffer, iSize + 8); */
|
||
DWORD * pdwWritePoint = (DWORD *) buffer_write_peek(m_lpOutputBuffer);
|
||
|
||
if (packet_encode(m_lpOutputBuffer, c_pvData, iSize))
|
||
{
|
||
int iSize2 = TEA_Encrypt(pdwWritePoint, pdwWritePoint, GetEncryptionKey(), iSize);
|
||
|
||
if (iSize2 > iSize)
|
||
buffer_write_proceed(m_lpOutputBuffer, iSize2 - iSize);
|
||
}
|
||
}
|
||
}
|
||
#endif // _IMPROVED_PACKET_ENCRYPTION_
|
||
|
||
SAFE_BUFFER_DELETE(m_lpBufferedOutputBuffer);
|
||
}
|
||
|
||
//sys_log(0, "%d bytes written (first byte %d)", iSize, *(BYTE *) c_pvData);
|
||
if (m_iPhase != PHASE_CLOSE)
|
||
fdwatch_add_fd(m_lpFdw, m_sock, this, FDW_WRITE, true);
|
||
}
|
||
|
||
void DESC::LargePacket(const void * c_pvData, int iSize)
|
||
{
|
||
buffer_adjust_size(m_lpOutputBuffer, iSize);
|
||
sys_log(0, "LargePacket Size %d", iSize, buffer_size(m_lpOutputBuffer));
|
||
|
||
Packet(c_pvData, iSize);
|
||
}
|
||
|
||
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:
|
||
#ifndef _IMPROVED_PACKET_ENCRYPTION_
|
||
m_bEncrypted = true;
|
||
#endif
|
||
m_pInputProcessor = &m_inputLogin;
|
||
break;
|
||
|
||
case PHASE_GAME:
|
||
case PHASE_DEAD:
|
||
#ifndef _IMPROVED_PACKET_ENCRYPTION_
|
||
m_bEncrypted = true;
|
||
#endif
|
||
m_pInputProcessor = &m_inputMain;
|
||
break;
|
||
|
||
case PHASE_AUTH:
|
||
#ifndef _IMPROVED_PACKET_ENCRYPTION_
|
||
m_bEncrypted = true;
|
||
#endif
|
||
m_pInputProcessor = &m_inputAuth;
|
||
sys_log(0, "AUTH_PHASE %p", this);
|
||
break;
|
||
}
|
||
}
|
||
|
||
void DESC::BindAccountTable(TAccountTable * pAccountTable)
|
||
{
|
||
assert(pAccountTable != NULL);
|
||
thecore_memcpy(&m_accountTable, pAccountTable, sizeof(TAccountTable));
|
||
DESC_MANAGER::instance().ConnectAccount(m_accountTable.login, this);
|
||
}
|
||
|
||
void DESC::UDPGrant(const struct sockaddr_in & c_rSockAddr)
|
||
{
|
||
m_UDPSockAddr = c_rSockAddr;
|
||
|
||
TPacketGCBindUDP pack;
|
||
|
||
pack.header = HEADER_GC_BINDUDP;
|
||
pack.addr = m_UDPSockAddr.sin_addr.s_addr;
|
||
pack.port = m_UDPSockAddr.sin_port;
|
||
|
||
Packet(&pack, sizeof(TPacketGCBindUDP));
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
#ifdef _IMPROVED_PACKET_ENCRYPTION_
|
||
void DESC::SendKeyAgreement()
|
||
{
|
||
TPacketKeyAgreement packet;
|
||
|
||
size_t data_length = TPacketKeyAgreement::MAX_DATA_LEN;
|
||
size_t agreed_length = cipher_.Prepare(packet.data, &data_length);
|
||
if (agreed_length == 0) {
|
||
// Initialization failure
|
||
SetPhase(PHASE_CLOSE);
|
||
return;
|
||
}
|
||
assert(data_length <= TPacketKeyAgreement::MAX_DATA_LEN);
|
||
|
||
packet.bHeader = HEADER_GC_KEY_AGREEMENT;
|
||
packet.wAgreedLength = (WORD)agreed_length;
|
||
packet.wDataLength = (WORD)data_length;
|
||
|
||
Packet(&packet, sizeof(packet));
|
||
}
|
||
|
||
void DESC::SendKeyAgreementCompleted()
|
||
{
|
||
TPacketKeyAgreementCompleted packet;
|
||
|
||
packet.bHeader = HEADER_GC_KEY_AGREEMENT_COMPLETED;
|
||
|
||
Packet(&packet, sizeof(packet));
|
||
}
|
||
|
||
bool DESC::FinishHandshake(size_t agreed_length, const void* buffer, size_t length)
|
||
{
|
||
return cipher_.Activate(false, agreed_length, buffer, length);
|
||
}
|
||
|
||
bool DESC::IsCipherPrepared()
|
||
{
|
||
return cipher_.IsKeyPrepared();
|
||
}
|
||
#endif // #ifdef _IMPROVED_PACKET_ENCRYPTION_
|
||
|
||
void DESC::SetRelay(const char * c_pszName)
|
||
{
|
||
m_stRelayName = c_pszName;
|
||
}
|
||
|
||
void DESC::BindCharacter(LPCHARACTER ch)
|
||
{
|
||
m_lpCharacter = ch;
|
||
}
|
||
|
||
void DESC::FlushOutput()
|
||
{
|
||
if (m_sock == INVALID_SOCKET) {
|
||
return;
|
||
}
|
||
|
||
if (buffer_size(m_lpOutputBuffer) <= 0)
|
||
return;
|
||
|
||
struct timeval sleep_tv, now_tv, start_tv;
|
||
int event_triggered = false;
|
||
|
||
gettimeofday(&start_tv, NULL);
|
||
|
||
socket_block(m_sock);
|
||
sys_log(0, "FLUSH START %d", buffer_size(m_lpOutputBuffer));
|
||
|
||
while (buffer_size(m_lpOutputBuffer) > 0)
|
||
{
|
||
gettimeofday(&now_tv, NULL);
|
||
|
||
int iSecondsPassed = now_tv.tv_sec - start_tv.tv_sec;
|
||
|
||
if (iSecondsPassed > 10)
|
||
{
|
||
if (!event_triggered || iSecondsPassed > 20)
|
||
{
|
||
SetPhase(PHASE_CLOSE);
|
||
break;
|
||
}
|
||
}
|
||
|
||
sleep_tv.tv_sec = 0;
|
||
sleep_tv.tv_usec = 10000;
|
||
|
||
int num_events = fdwatch(m_lpFdw, &sleep_tv);
|
||
|
||
if (num_events < 0)
|
||
{
|
||
sys_err("num_events < 0 : %d", num_events);
|
||
break;
|
||
}
|
||
|
||
int event_idx;
|
||
|
||
for (event_idx = 0; event_idx < num_events; ++event_idx)
|
||
{
|
||
LPDESC d2 = (LPDESC) fdwatch_get_client_data(m_lpFdw, event_idx);
|
||
|
||
if (d2 != this)
|
||
continue;
|
||
|
||
switch (fdwatch_check_event(m_lpFdw, m_sock, event_idx))
|
||
{
|
||
case FDW_WRITE:
|
||
event_triggered = true;
|
||
|
||
if (ProcessOutput() < 0)
|
||
{
|
||
sys_err("Cannot flush output buffer");
|
||
SetPhase(PHASE_CLOSE);
|
||
}
|
||
break;
|
||
|
||
case FDW_EOF:
|
||
SetPhase(PHASE_CLOSE);
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (IsPhase(PHASE_CLOSE))
|
||
break;
|
||
}
|
||
|
||
if (buffer_size(m_lpOutputBuffer) == 0)
|
||
sys_log(0, "FLUSH SUCCESS");
|
||
else
|
||
sys_log(0, "FLUSH FAIL");
|
||
|
||
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
|
||
thecore_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();
|
||
strlcpy(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 long rows, unsigned long cols)
|
||
{
|
||
m_dwMatrixRows = rows;
|
||
m_dwMatrixCols = cols;
|
||
}
|
||
|
||
unsigned long DESC::GetMatrixRows()
|
||
{
|
||
return m_dwMatrixRows;
|
||
}
|
||
|
||
unsigned long 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;
|
||
}
|
||
|
||
#ifndef _IMPROVED_PACKET_ENCRYPTION_
|
||
void DESC::SetSecurityKey(const DWORD * c_pdwKey)
|
||
{
|
||
const BYTE * c_pszKey = (const BYTE *) "JyTxtHljHJlVJHorRM301vf@4fvj10-v";
|
||
|
||
if (g_iUseLocale && !LC_IsKorea())
|
||
c_pszKey = GetKey_20050304Myevan() + 37;
|
||
|
||
thecore_memcpy(&m_adwDecryptionKey, c_pdwKey, 16);
|
||
TEA_Encrypt(&m_adwEncryptionKey[0], &m_adwDecryptionKey[0], (const DWORD *) c_pszKey, 16);
|
||
|
||
sys_log(0, "SetSecurityKey decrypt %u %u %u %u encrypt %u %u %u %u",
|
||
m_adwDecryptionKey[0], m_adwDecryptionKey[1], m_adwDecryptionKey[2], m_adwDecryptionKey[3],
|
||
m_adwEncryptionKey[0], m_adwEncryptionKey[1], m_adwEncryptionKey[2], m_adwEncryptionKey[3]);
|
||
}
|
||
#endif // _IMPROVED_PACKET_ENCRYPTION_
|
||
|
||
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());
|
||
}
|
||
|