forked from metin-server/m2dev-client-src
986 lines
24 KiB
C++
986 lines
24 KiB
C++
#include "StdAfx.h"
|
|
#include "NetStream.h"
|
|
//#include "eterCrypt.h"
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
|
|
#ifndef _IMPROVED_PACKET_ENCRYPTION_
|
|
#include "EterBase/tea.h"
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
|
#define _PACKETDUMP
|
|
#endif
|
|
|
|
#ifndef _IMPROVED_PACKET_ENCRYPTION_
|
|
void CNetworkStream::SetSecurityMode(bool isSecurityMode, const char* c_szTeaKey)
|
|
{
|
|
m_isSecurityMode = isSecurityMode;
|
|
memcpy(m_szEncryptKey, c_szTeaKey, TEA_KEY_LENGTH);
|
|
memcpy(m_szDecryptKey, c_szTeaKey, TEA_KEY_LENGTH);
|
|
}
|
|
|
|
void CNetworkStream::SetSecurityMode(bool isSecurityMode, const char* c_szTeaEncryptKey, const char* c_szTeaDecryptKey)
|
|
{
|
|
m_isSecurityMode = isSecurityMode;
|
|
memcpy(m_szEncryptKey, c_szTeaEncryptKey, TEA_KEY_LENGTH);
|
|
memcpy(m_szDecryptKey, c_szTeaDecryptKey, TEA_KEY_LENGTH);
|
|
}
|
|
#endif // _IMPROVED_PACKET_ENCRYPTION_
|
|
|
|
bool CNetworkStream::IsSecurityMode()
|
|
{
|
|
#ifdef _IMPROVED_PACKET_ENCRYPTION_
|
|
return m_cipher.activated();
|
|
#else
|
|
return m_isSecurityMode;
|
|
#endif
|
|
}
|
|
|
|
void CNetworkStream::SetRecvBufferSize(int recvBufSize)
|
|
{
|
|
if (m_recvBuf)
|
|
{
|
|
if (m_recvBufSize>recvBufSize)
|
|
return;
|
|
|
|
delete [] m_recvBuf;
|
|
|
|
if (m_recvTEABuf)
|
|
delete [] m_recvTEABuf;
|
|
}
|
|
m_recvBufSize = recvBufSize;
|
|
m_recvBuf = new char[m_recvBufSize];
|
|
m_recvTEABufSize = ((m_recvBufSize>>3)+1)<<3;
|
|
m_recvTEABuf = new char[m_recvTEABufSize];
|
|
}
|
|
|
|
void CNetworkStream::SetSendBufferSize(int sendBufSize)
|
|
{
|
|
if (m_sendBuf)
|
|
{
|
|
if (m_sendBufSize > sendBufSize)
|
|
return;
|
|
|
|
delete [] m_sendBuf;
|
|
|
|
if (m_sendTEABuf)
|
|
delete [] m_sendTEABuf;
|
|
}
|
|
|
|
m_sendBufSize = sendBufSize;
|
|
m_sendBuf = new char[m_sendBufSize];
|
|
m_sendTEABufSize = ((m_sendBufSize>>3)+1)<<3;
|
|
m_sendTEABuf = new char[m_sendTEABufSize];
|
|
}
|
|
|
|
bool CNetworkStream::__RecvInternalBuffer()
|
|
{
|
|
if (m_recvBufOutputPos>0)
|
|
{
|
|
int recvBufDataSize = m_recvBufInputPos - m_recvBufOutputPos;
|
|
if (recvBufDataSize>0)
|
|
{
|
|
memmove(m_recvBuf, m_recvBuf + m_recvBufOutputPos, recvBufDataSize);
|
|
}
|
|
|
|
m_recvBufInputPos -= m_recvBufOutputPos;
|
|
m_recvBufOutputPos = 0;
|
|
}
|
|
|
|
#ifdef _IMPROVED_PACKET_ENCRYPTION_
|
|
int restSize = m_recvBufSize - m_recvBufInputPos;
|
|
if (restSize>0)
|
|
{
|
|
int recvSize = recv(m_sock, m_recvBuf + m_recvBufInputPos, m_recvBufSize - m_recvBufInputPos, 0);
|
|
//Tracenf("RECV %d %d(%d, %d)", recvSize, restSize, m_recvTEABufSize - m_recvTEABufInputPos, m_recvBufSize - m_recvBufInputPos);
|
|
|
|
if (recvSize < 0)
|
|
{
|
|
int error = WSAGetLastError();
|
|
|
|
if (error != WSAEWOULDBLOCK)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else if (recvSize == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (IsSecurityMode()) {
|
|
m_cipher.Decrypt(m_recvBuf + m_recvBufInputPos, recvSize);
|
|
}
|
|
|
|
m_recvBufInputPos += recvSize;
|
|
}
|
|
#else
|
|
if (IsSecurityMode())
|
|
{
|
|
int restSize = std::min(m_recvTEABufSize - m_recvTEABufInputPos, m_recvBufSize - m_recvBufInputPos);
|
|
|
|
if (restSize > 0)
|
|
{
|
|
int recvSize = recv(m_sock, m_recvTEABuf + m_recvTEABufInputPos, restSize, 0);
|
|
//Tracenf("RECV %d %d(%d, %d)", recvSize, restSize, m_recvTEABufSize - m_recvTEABufInputPos, m_recvBufSize - m_recvBufInputPos);
|
|
|
|
if (recvSize < 0)
|
|
{
|
|
int error = WSAGetLastError();
|
|
|
|
if (error != WSAEWOULDBLOCK)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else if (recvSize == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_recvTEABufInputPos += recvSize;
|
|
|
|
int decodeSize = m_recvTEABufInputPos;
|
|
|
|
if (decodeSize >= 8)
|
|
{
|
|
decodeSize >>= 3;
|
|
decodeSize <<= 3;
|
|
|
|
/*int decodeDstSize = tea_decrypt((DWORD *) (m_recvBuf + m_recvBufInputPos),
|
|
(DWORD *) m_recvTEABuf,
|
|
(const DWORD *) m_szDecryptKey,
|
|
decodeSize);
|
|
*/
|
|
int decodeDstSize = tea_decrypt((DWORD *) (m_recvBuf + m_recvBufInputPos),
|
|
(DWORD *) m_recvTEABuf,
|
|
(const DWORD *) m_szDecryptKey,
|
|
decodeSize);
|
|
|
|
m_recvBufInputPos += decodeDstSize;
|
|
|
|
if (m_recvTEABufInputPos>decodeSize)
|
|
memmove(m_recvTEABuf, m_recvTEABuf+decodeSize, m_recvTEABufInputPos-decodeSize);
|
|
|
|
m_recvTEABufInputPos -= decodeSize;
|
|
|
|
|
|
//Tracenf("!!!!!! decrypt decodeSrcSize %d -> decodeDstSize %d (recvOutputPos %d, recvInputPos %d, teaInputPos %d)",
|
|
// decodeSize, decodeDstSize, m_recvBufOutputPos, m_recvBufInputPos, m_recvTEABufInputPos);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int restSize = m_recvBufSize - m_recvBufInputPos;
|
|
if (restSize>0)
|
|
{
|
|
int recvSize = recv(m_sock, m_recvBuf + m_recvBufInputPos, m_recvBufSize - m_recvBufInputPos, 0);
|
|
//Tracenf("RECV %d %d(%d, %d)", recvSize, restSize, m_recvTEABufSize - m_recvTEABufInputPos, m_recvBufSize - m_recvBufInputPos);
|
|
|
|
if (recvSize < 0)
|
|
{
|
|
int error = WSAGetLastError();
|
|
|
|
if (error != WSAEWOULDBLOCK)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else if (recvSize == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_recvBufInputPos += recvSize;
|
|
}
|
|
}
|
|
#endif // _IMPROVED_PACKET_ENCRYPTION_
|
|
|
|
//Tracef("recvSize: %d input pos %d output pos %d\n", recvSize, m_recvBufInputPos, m_recvBufOutputPos);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CNetworkStream::__SendInternalBuffer()
|
|
{
|
|
#ifdef _IMPROVED_PACKET_ENCRYPTION_
|
|
int dataSize=__GetSendBufferSize();
|
|
if (dataSize<=0)
|
|
return true;
|
|
|
|
if (IsSecurityMode()) {
|
|
m_cipher.Encrypt(m_sendBuf + m_sendBufOutputPos, dataSize);
|
|
}
|
|
|
|
int sendSize = send(m_sock, m_sendBuf+m_sendBufOutputPos, dataSize, 0);
|
|
if (sendSize < 0)
|
|
return false;
|
|
|
|
m_sendBufOutputPos+=sendSize;
|
|
|
|
__PopSendBuffer();
|
|
#else
|
|
if (IsSecurityMode())
|
|
{
|
|
int encodeSize=__GetSendBufferSize();
|
|
if (encodeSize<=0)
|
|
return true;
|
|
|
|
m_sendTEABufInputPos += tea_encrypt((DWORD *) (m_sendTEABuf + m_sendTEABufInputPos),
|
|
(DWORD *) (m_sendBuf + m_sendBufOutputPos),
|
|
(const DWORD *) m_szEncryptKey,
|
|
encodeSize);
|
|
m_sendBufOutputPos += encodeSize;
|
|
|
|
if (m_sendTEABufInputPos>0)
|
|
{
|
|
int sendSize = send(m_sock, m_sendTEABuf, m_sendTEABufInputPos, 0);
|
|
if (sendSize < 0)
|
|
return false;
|
|
|
|
if (m_sendTEABufInputPos>sendSize)
|
|
memmove(m_sendTEABuf, m_sendTEABuf+sendSize, m_sendTEABufInputPos-sendSize);
|
|
|
|
m_sendTEABufInputPos-=sendSize;
|
|
}
|
|
|
|
__PopSendBuffer();
|
|
}
|
|
else
|
|
{
|
|
int dataSize=__GetSendBufferSize();
|
|
if (dataSize<=0)
|
|
return true;
|
|
|
|
int sendSize = send(m_sock, m_sendBuf+m_sendBufOutputPos, dataSize, 0);
|
|
if (sendSize < 0)
|
|
return false;
|
|
|
|
m_sendBufOutputPos+=sendSize;
|
|
|
|
__PopSendBuffer();
|
|
}
|
|
#endif // _IMPROVED_PACKET_ENCRYPTION_
|
|
|
|
return true;
|
|
}
|
|
|
|
void CNetworkStream::__PopSendBuffer()
|
|
{
|
|
if (m_sendBufOutputPos<=0)
|
|
return;
|
|
|
|
int sendBufDataSize = m_sendBufInputPos - m_sendBufOutputPos;
|
|
|
|
if (sendBufDataSize>0)
|
|
{
|
|
memmove(m_sendBuf, m_sendBuf+m_sendBufOutputPos, sendBufDataSize);
|
|
}
|
|
|
|
m_sendBufInputPos = sendBufDataSize;
|
|
m_sendBufOutputPos = 0;
|
|
}
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable:4127)
|
|
void CNetworkStream::Process()
|
|
{
|
|
if (m_sock == INVALID_SOCKET)
|
|
return;
|
|
|
|
fd_set fdsRecv;
|
|
fd_set fdsSend;
|
|
|
|
FD_ZERO(&fdsRecv);
|
|
FD_ZERO(&fdsSend);
|
|
|
|
FD_SET(m_sock, &fdsRecv);
|
|
FD_SET(m_sock, &fdsSend);
|
|
|
|
TIMEVAL delay;
|
|
|
|
delay.tv_sec = 0;
|
|
delay.tv_usec = 0;
|
|
|
|
if (select(0, &fdsRecv, &fdsSend, NULL, &delay) == SOCKET_ERROR)
|
|
return;
|
|
|
|
if (!m_isOnline)
|
|
{
|
|
if (FD_ISSET(m_sock, &fdsSend))
|
|
{
|
|
m_isOnline = true;
|
|
OnConnectSuccess();
|
|
}
|
|
else if (time(NULL) > m_connectLimitTime)
|
|
{
|
|
Clear();
|
|
OnConnectFailure();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (FD_ISSET(m_sock, &fdsSend) && (m_sendBufInputPos > m_sendBufOutputPos))
|
|
{
|
|
if (!__SendInternalBuffer())
|
|
{
|
|
int error = WSAGetLastError();
|
|
|
|
if (error != WSAEWOULDBLOCK)
|
|
{
|
|
OnRemoteDisconnect();
|
|
Clear();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FD_ISSET(m_sock, &fdsRecv))
|
|
{
|
|
if (!__RecvInternalBuffer())
|
|
{
|
|
OnRemoteDisconnect();
|
|
Clear();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!OnProcess())
|
|
{
|
|
OnRemoteDisconnect();
|
|
Clear();
|
|
}
|
|
}
|
|
#pragma warning(pop)
|
|
|
|
void CNetworkStream::Disconnect()
|
|
{
|
|
if (m_sock == INVALID_SOCKET)
|
|
return;
|
|
|
|
//OnDisconnect();
|
|
|
|
Clear();
|
|
}
|
|
|
|
void CNetworkStream::Clear()
|
|
{
|
|
if (m_sock == INVALID_SOCKET)
|
|
return;
|
|
|
|
#ifdef _IMPROVED_PACKET_ENCRYPTION_
|
|
m_cipher.CleanUp();
|
|
#endif
|
|
|
|
closesocket(m_sock);
|
|
m_sock = INVALID_SOCKET;
|
|
|
|
#ifndef _IMPROVED_PACKET_ENCRYPTION_
|
|
memset(m_szEncryptKey, 0, sizeof(m_szEncryptKey));
|
|
memset(m_szDecryptKey, 0, sizeof(m_szDecryptKey));
|
|
|
|
m_isSecurityMode = false;
|
|
#endif
|
|
|
|
m_isOnline = false;
|
|
m_connectLimitTime = 0;
|
|
|
|
m_recvTEABufInputPos = 0;
|
|
m_sendTEABufInputPos = 0;
|
|
|
|
m_recvBufInputPos = 0;
|
|
m_recvBufOutputPos = 0;
|
|
|
|
m_sendBufInputPos = 0;
|
|
m_sendBufOutputPos = 0;
|
|
|
|
m_SequenceGenerator.seed(SEQUENCE_SEED);
|
|
}
|
|
|
|
bool CNetworkStream::Connect(const CNetworkAddress& c_rkNetAddr, int limitSec)
|
|
{
|
|
Clear();
|
|
|
|
m_addr = c_rkNetAddr;
|
|
|
|
m_sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (m_sock == INVALID_SOCKET)
|
|
{
|
|
Clear();
|
|
OnConnectFailure();
|
|
return false;
|
|
}
|
|
|
|
DWORD arg = 1;
|
|
ioctlsocket(m_sock, FIONBIO, &arg); // Non-blocking mode
|
|
|
|
// Enable TCP_NODELAY to disable Nagle's algorithm for lower latency
|
|
int opt = 1;
|
|
if (setsockopt(m_sock, IPPROTO_TCP, TCP_NODELAY, (const char*)&opt, sizeof(opt)) != 0)
|
|
{
|
|
TraceError("setsockopt TCP_NODELAY failed: %d", WSAGetLastError());
|
|
}
|
|
|
|
if (connect(m_sock, (PSOCKADDR)&m_addr, m_addr.GetSize()) == SOCKET_ERROR)
|
|
{
|
|
int error = WSAGetLastError();
|
|
|
|
if (error != WSAEWOULDBLOCK)
|
|
{
|
|
Tracen("error != WSAEWOULDBLOCK");
|
|
Clear();
|
|
OnConnectFailure();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
m_connectLimitTime = time(NULL) + limitSec;
|
|
return true;
|
|
}
|
|
|
|
bool CNetworkStream::Connect(DWORD dwAddr, int port, int limitSec)
|
|
{
|
|
char szAddr[256];
|
|
{
|
|
BYTE ip[4];
|
|
ip[0]=dwAddr&0xff;dwAddr>>=8;
|
|
ip[1]=dwAddr&0xff;dwAddr>>=8;
|
|
ip[2]=dwAddr&0xff;dwAddr>>=8;
|
|
ip[3]=dwAddr&0xff;dwAddr>>=8;
|
|
|
|
sprintf(szAddr, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
|
|
}
|
|
|
|
return Connect(szAddr, port, limitSec);
|
|
}
|
|
|
|
bool CNetworkStream::Connect(const char* c_szAddr, int port, int /*limitSec*/)
|
|
{
|
|
CNetworkAddress kNetAddr;
|
|
kNetAddr.Set(c_szAddr, port);
|
|
|
|
return Connect(kNetAddr);
|
|
}
|
|
|
|
void CNetworkStream::ClearRecvBuffer()
|
|
{
|
|
m_recvBufOutputPos = m_recvBufInputPos = 0;
|
|
}
|
|
|
|
int CNetworkStream::GetRecvBufferSize()
|
|
{
|
|
return m_recvBufInputPos - m_recvBufOutputPos;
|
|
}
|
|
|
|
bool CNetworkStream::Peek(int size)
|
|
{
|
|
if (GetRecvBufferSize() < size)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CNetworkStream::Peek(int size, char * pDestBuf)
|
|
{
|
|
if (GetRecvBufferSize() < size)
|
|
return false;
|
|
|
|
memcpy(pDestBuf, m_recvBuf + m_recvBufOutputPos, size);
|
|
return true;
|
|
}
|
|
|
|
|
|
#ifdef _PACKETDUMP
|
|
const char * GetSendHeaderName(BYTE header)
|
|
{
|
|
static bool b = false;
|
|
static std::string stringList[UCHAR_MAX+1];
|
|
if (b==false)
|
|
{
|
|
for (DWORD i = 0; i < UCHAR_MAX+1; i++)
|
|
{
|
|
char buf[10];
|
|
sprintf(buf,"%d",i);
|
|
stringList[i] = buf;
|
|
}
|
|
stringList[1] = "HEADER_CG_LOGIN";
|
|
stringList[2] = "HEADER_CG_ATTACK";
|
|
stringList[3] = "HEADER_CG_CHAT";
|
|
stringList[4] = "HEADER_CG_PLAYER_CREATE";
|
|
stringList[5] = "HEADER_CG_PLAYER_DESTROY";
|
|
stringList[6] = "HEADER_CG_PLAYER_SELECT";
|
|
stringList[7] = "HEADER_CG_CHARACTER_MOVE";
|
|
stringList[8] = "HEADER_CG_SYNC_POSITION";
|
|
stringList[9] = "HEADER_CG_DIRECT_ENTER";
|
|
stringList[10] = "HEADER_CG_ENTERGAME";
|
|
stringList[11] = "HEADER_CG_ITEM_USE";
|
|
stringList[12] = "HEADER_CG_ITEM_DROP";
|
|
stringList[13] = "HEADER_CG_ITEM_MOVE";
|
|
stringList[15] = "HEADER_CG_ITEM_PICKUP";
|
|
stringList[16] = "HEADER_CG_QUICKSLOT_ADD";
|
|
stringList[17] = "HEADER_CG_QUICKSLOT_DEL";
|
|
stringList[18] = "HEADER_CG_QUICKSLOT_SWAP";
|
|
stringList[19] = "HEADER_CG_WHISPER";
|
|
stringList[20] = "HEADER_CG_ITEM_DROP2";
|
|
stringList[26] = "HEADER_CG_ON_CLICK";
|
|
stringList[27] = "HEADER_CG_EXCHANGE";
|
|
stringList[28] = "HEADER_CG_CHARACTER_POSITION";
|
|
stringList[29] = "HEADER_CG_SCRIPT_ANSWER";
|
|
stringList[30] = "HEADER_CG_QUEST_INPUT_STRING";
|
|
stringList[31] = "HEADER_CG_QUEST_CONFIRM";
|
|
stringList[41] = "HEADER_CG_PVP";
|
|
stringList[50] = "HEADER_CG_SHOP";
|
|
stringList[51] = "HEADER_CG_FLY_TARGETING";
|
|
stringList[52] = "HEADER_CG_USE_SKILL";
|
|
stringList[53] = "HEADER_CG_ADD_FLY_TARGETING";
|
|
stringList[54] = "HEADER_CG_SHOOT";
|
|
stringList[55] = "HEADER_CG_MYSHOP";
|
|
stringList[60] = "HEADER_CG_ITEM_USE_TO_ITEM";
|
|
stringList[61] = "HEADER_CG_TARGET";
|
|
stringList[65] = "HEADER_CG_WARP";
|
|
stringList[66] = "HEADER_CG_SCRIPT_BUTTON";
|
|
stringList[67] = "HEADER_CG_MESSENGER";
|
|
stringList[69] = "HEADER_CG_MALL_CHECKOUT";
|
|
stringList[70] = "HEADER_CG_SAFEBOX_CHECKIN";
|
|
stringList[71] = "HEADER_CG_SAFEBOX_CHECKOUT";
|
|
stringList[72] = "HEADER_CG_PARTY_INVITE";
|
|
stringList[73] = "HEADER_CG_PARTY_INVITE_ANSWER";
|
|
stringList[74] = "HEADER_CG_PARTY_REMOVE";
|
|
stringList[75] = "HEADER_CG_PARTY_SET_STATE";
|
|
stringList[76] = "HEADER_CG_PARTY_USE_SKILL";
|
|
stringList[77] = "HEADER_CG_SAFEBOX_ITEM_MOVE";
|
|
stringList[78] = "HEADER_CG_PARTY_PARAMETER";
|
|
stringList[80] = "HEADER_CG_GUILD";
|
|
stringList[81] = "HEADER_CG_ANSWER_MAKE_GUILD";
|
|
stringList[82] = "HEADER_CG_FISHING";
|
|
stringList[83] = "HEADER_CG_GIVE_ITEM";
|
|
stringList[90] = "HEADER_CG_EMPIRE";
|
|
stringList[96] = "HEADER_CG_REFINE";
|
|
stringList[100] = "HEADER_CG_MARK_LOGIN";
|
|
stringList[101] = "HEADER_CG_MARK_CRCLIST";
|
|
stringList[102] = "HEADER_CG_MARK_UPLOAD";
|
|
stringList[103] = "HEADER_CG_CRC_REPORT";
|
|
stringList[105] = "HEADER_CG_HACK";
|
|
stringList[106] = "HEADER_CG_CHANGE_NAME";
|
|
stringList[107] = "HEADER_CG_SMS";
|
|
stringList[108] = "HEADER_CG_MATRIX_CARD";
|
|
stringList[109] = "HEADER_CG_LOGIN2";
|
|
stringList[110] = "HEADER_CG_DUNGEON";
|
|
stringList[111] = "HEADER_CG_LOGIN3";
|
|
stringList[112] = "HEADER_CG_GUILD_SYMBOL_UPLOAD";
|
|
stringList[113] = "HEADER_CG_GUILD_SYMBOL_CRC";
|
|
stringList[114] = "HEADER_CG_SCRIPT_SELECT_ITEM";
|
|
#ifdef _IMPROVED_PACKET_ENCRYPTION_
|
|
stringList[0xfb] = "HEADER_CG_KEY_AGREEMENT";
|
|
#endif
|
|
stringList[0xfc] = "HEADER_CG_TIME_SYNC";
|
|
stringList[0xfd] = "HEADER_CG_CLIENT_VERSION";
|
|
stringList[0xfe] = "HEADER_CG_PONG";
|
|
stringList[0xff] = "HEADER_CG_HANDSHAKE";
|
|
}
|
|
return stringList[header].c_str();
|
|
}
|
|
|
|
const char * GetRecvHeaderName(BYTE header)
|
|
{
|
|
static bool b = false;
|
|
static std::string stringList[UCHAR_MAX+1];
|
|
if (b==false)
|
|
{
|
|
for (DWORD i = 0; i < UCHAR_MAX+1; i++)
|
|
{
|
|
char buf[10];
|
|
sprintf(buf,"%d",i);
|
|
stringList[i] = buf;
|
|
}
|
|
stringList[1] = "HEADER_GC_CHARACTER_ADD";
|
|
stringList[2] = "HEADER_GC_CHARACTER_DEL";
|
|
stringList[3] = "HEADER_GC_CHARACTER_MOVE";
|
|
stringList[4] = "HEADER_GC_CHAT";
|
|
stringList[5] = "HEADER_GC_SYNC_POSITION";
|
|
stringList[6] = "HEADER_GC_LOGIN_SUCCESS";
|
|
stringList[7] = "HEADER_GC_LOGIN_FAILURE";
|
|
stringList[8] = "HEADER_GC_PLAYER_CREATE_SUCCESS";
|
|
stringList[9] = "HEADER_GC_PLAYER_CREATE_FAILURE";
|
|
stringList[10] = "HEADER_GC_PLAYER_DELETE_SUCCESS";
|
|
stringList[11] = "HEADER_GC_PLAYER_DELETE_WRONG_SOCIAL_ID";
|
|
|
|
stringList[13] = "HEADER_GC_STUN";
|
|
stringList[14] = "HEADER_GC_DEAD";
|
|
stringList[15] = "HEADER_GC_MAIN_CHARACTER";
|
|
stringList[16] = "HEADER_GC_PLAYER_POINTS";
|
|
stringList[17] = "HEADER_GC_PLAYER_POINT_CHANGE";
|
|
stringList[18] = "HEADER_GC_CHANGE_SPEED";
|
|
stringList[19] = "HEADER_GC_CHARACTER_UPDATE";
|
|
stringList[20] = "HEADER_GC_ITEM_DEL";
|
|
stringList[21] = "HEADER_GC_ITEM_SET";
|
|
stringList[22] = "HEADER_GC_ITEM_USE";
|
|
stringList[23] = "HEADER_GC_ITEM_DROP";
|
|
stringList[25] = "HEADER_GC_ITEM_UPDATE";
|
|
stringList[26] = "HEADER_GC_ITEM_GROUND_ADD";
|
|
stringList[27] = "HEADER_GC_ITEM_GROUND_DEL";
|
|
stringList[28] = "HEADER_GC_QUICKSLOT_ADD";
|
|
stringList[29] = "HEADER_GC_QUICKSLOT_DEL";
|
|
stringList[30] = "HEADER_GC_QUICKSLOT_SWAP";
|
|
stringList[31] = "HEADER_GC_ITEM_OWNERSHIP";
|
|
stringList[33] = "HEADER_GC_ITEM_UNBIND_TIME";
|
|
stringList[34] = "HEADER_GC_WHISPER ";
|
|
stringList[35] = "HEADER_GC_ALERT";
|
|
stringList[36] = "HEADER_GC_MOTION";
|
|
stringList[38] = "HEADER_GC_SHOP";
|
|
stringList[39] = "HEADER_GC_SHOP_SIGN";
|
|
stringList[41] = "HEADER_GC_PVP";
|
|
stringList[42] = "HEADER_GC_EXCHANGE";
|
|
stringList[43] = "HEADER_GC_CHARACTER_POSITION";
|
|
stringList[44] = "HEADER_GC_PING";
|
|
stringList[45] = "HEADER_GC_SCRIPT";
|
|
stringList[46] = "HEADER_GC_QUEST_CONFIRM";
|
|
|
|
stringList[61] = "HEADER_GC_MOUNT";
|
|
stringList[62] = "HEADER_GC_OWNERSHIP";
|
|
stringList[63] = "HEADER_GC_TARGET";
|
|
stringList[65] = "HEADER_GC_WARP";
|
|
stringList[69] = "HEADER_GC_ADD_FLY_TARGETING";
|
|
|
|
stringList[70] = "HEADER_GC_CREATE_FLY";
|
|
stringList[71] = "HEADER_GC_FLY_TARGETING";
|
|
stringList[72] = "HEADER_GC_SKILL_LEVEL";
|
|
stringList[73] = "HEADER_GC_SKILL_COOLTIME_END";
|
|
stringList[74] = "HEADER_GC_MESSENGER";
|
|
stringList[75] = "HEADER_GC_GUILD";
|
|
stringList[76] = "HEADER_GC_SKILL_LEVEL_NEW";
|
|
stringList[77] = "HEADER_GC_PARTY_INVITE";
|
|
stringList[78] = "HEADER_GC_PARTY_ADD";
|
|
stringList[79] = "HEADER_GC_PARTY_UPDATE";
|
|
stringList[80] = "HEADER_GC_PARTY_REMOVE";
|
|
stringList[81] = "HEADER_GC_QUEST_INFO";
|
|
stringList[82] = "HEADER_GC_REQUEST_MAKE_GUILD";
|
|
stringList[83] = "HEADER_GC_PARTY_PARAMETER";
|
|
stringList[84] = "HEADER_GC_SAFEBOX_MONEY_CHANGE";
|
|
stringList[85] = "HEADER_GC_SAFEBOX_SET";
|
|
stringList[86] = "HEADER_GC_SAFEBOX_DEL";
|
|
stringList[87] = "HEADER_GC_SAFEBOX_WRONG_PASSWORD";
|
|
stringList[88] = "HEADER_GC_SAFEBOX_SIZE";
|
|
stringList[89] = "HEADER_GC_FISHING";
|
|
stringList[90] = "HEADER_GC_EMPIRE";
|
|
stringList[91] = "HEADER_GC_PARTY_LINK";
|
|
stringList[92] = "HEADER_GC_PARTY_UNLINK";
|
|
|
|
stringList[95] = "HEADER_GC_REFINE_INFORMATION";
|
|
stringList[96] = "HEADER_GC_OBSERVER_ADD";
|
|
stringList[97] = "HEADER_GC_OBSERVER_REMOVE";
|
|
stringList[98] = "HEADER_GC_OBSERVER_MOVE";
|
|
stringList[99] = "HEADER_GC_VIEW_EQUIP";
|
|
stringList[100] = "HEADER_GC_MARK_BLOCK";
|
|
stringList[101] = "HEADER_GC_MARK_DIFF_DATA";
|
|
|
|
stringList[106] = "HEADER_GC_TIME";
|
|
stringList[107] = "HEADER_GC_CHANGE_NAME";
|
|
stringList[110] = "HEADER_GC_DUNGEON";
|
|
stringList[111] = "HEADER_GC_WALK_MODE";
|
|
stringList[112] = "HEADER_GC_CHANGE_SKILL_GROUP";
|
|
stringList[113] = "HEADER_GC_MAIN_CHARACTER_NEW";
|
|
stringList[114] = "HEADER_GC_USE_POTION";
|
|
stringList[115] = "HEADER_GC_NPC_POSITION";
|
|
stringList[116] = "HEADER_GC_MATRIX_CARD";
|
|
stringList[117] = "HEADER_GC_CHARACTER_UPDATE2";
|
|
stringList[118] = "HEADER_GC_LOGIN_KEY";
|
|
stringList[119] = "HEADER_GC_REFINE_INFORMATION_NEW";
|
|
stringList[120] = "HEADER_GC_CHARACTER_ADD2";
|
|
stringList[121] = "HEADER_GC_CHANNEL";
|
|
stringList[122] = "HEADER_GC_MALL_OPEN";
|
|
stringList[123] = "HEADER_GC_TARGET_UPDATE";
|
|
stringList[124] = "HEADER_GC_TARGET_DELETE";
|
|
stringList[125] = "HEADER_GC_TARGET_CREATE_NEW";
|
|
stringList[126] = "HEADER_GC_AFFECT_ADD";
|
|
stringList[127] = "HEADER_GC_AFFECT_REMOVE";
|
|
stringList[128] = "HEADER_GC_MALL_SET";
|
|
stringList[129] = "HEADER_GC_MALL_DEL";
|
|
stringList[130] = "HEADER_GC_LAND_LIST";
|
|
stringList[131] = "HEADER_GC_LOVER_INFO";
|
|
stringList[132] = "HEADER_GC_LOVE_POINT_UPDATE";
|
|
stringList[133] = "HEADER_GC_GUILD_SYMBOL_DATA";
|
|
stringList[134] = "HEADER_GC_DIG_MOTION";
|
|
stringList[135] = "HEADER_GC_DAMAGE_INFO";
|
|
stringList[136] = "HEADER_GC_CHAR_ADDITIONAL_INFO";
|
|
stringList[150] = "HEADER_GC_AUTH_SUCCESS";
|
|
#ifdef _IMPROVED_PACKET_ENCRYPTION_
|
|
stringList[0xfa] = "HEADER_GC_KEY_AGREEMENT_COMPLETED";
|
|
stringList[0xfb] = "HEADER_GC_KEY_AGREEMENT";
|
|
#endif
|
|
stringList[0xfc] = "HEADER_GC_HANDSHAKE_OK";
|
|
stringList[0xfd] = "HEADER_GC_PHASE";
|
|
stringList[0xfe] = "HEADER_GC_BINDUDP";
|
|
stringList[0xff] = "HEADER_GC_HANDSHAKE";
|
|
}
|
|
return stringList[header].c_str();
|
|
}
|
|
|
|
#endif
|
|
|
|
bool CNetworkStream::Recv(int size)
|
|
{
|
|
if (!Peek(size))
|
|
return false;
|
|
|
|
m_recvBufOutputPos += size;
|
|
return true;
|
|
}
|
|
|
|
static std::string dump_hex(const uint8_t* ptr, const std::size_t length)
|
|
{
|
|
if (!ptr || !length)
|
|
return {};
|
|
|
|
std::stringstream ss;
|
|
|
|
std::vector <uint8_t> buffer(length);
|
|
memcpy(&buffer[0], ptr, length);
|
|
|
|
for (size_t i = 0; i < length; ++i)
|
|
ss << std::hex << std::setfill('0') << std::setw(2) << (int)buffer.at(i) << ", ";
|
|
|
|
const auto str = ss.str();
|
|
return str.substr(0, str.size() - 2);
|
|
}
|
|
|
|
bool CNetworkStream::Recv(int size, char * pDestBuf)
|
|
{
|
|
if (!Peek(size, pDestBuf))
|
|
return false;
|
|
|
|
#ifdef _PACKETDUMP
|
|
if (*pDestBuf != 0)
|
|
{
|
|
const auto kHeader = *pDestBuf;
|
|
TraceError("RECV< %s %u(0x%X) (%d)", GetRecvHeaderName(kHeader), kHeader, kHeader, size);
|
|
|
|
const auto contents = dump_hex(reinterpret_cast<const uint8_t*>(pDestBuf), size);
|
|
TraceError("%s", contents.c_str());
|
|
}
|
|
#endif
|
|
|
|
m_recvBufOutputPos += size;
|
|
return true;
|
|
}
|
|
|
|
int CNetworkStream::__GetSendBufferSize()
|
|
{
|
|
return m_sendBufInputPos-m_sendBufOutputPos;
|
|
}
|
|
|
|
|
|
bool CNetworkStream::Send(int size, const char * pSrcBuf)
|
|
{
|
|
int sendBufRestSize = m_sendBufSize - m_sendBufInputPos;
|
|
if ((size + 1) > sendBufRestSize)
|
|
return false;
|
|
|
|
memcpy(m_sendBuf + m_sendBufInputPos, pSrcBuf, size);
|
|
m_sendBufInputPos += size;
|
|
|
|
#ifdef _PACKETDUMP
|
|
if (*pSrcBuf != 0)
|
|
{
|
|
const auto kHeader = *pSrcBuf;
|
|
TraceError("SEND> %s %u(0x%X) (%d)", GetSendHeaderName(kHeader), kHeader, kHeader, size);
|
|
|
|
const auto contents = dump_hex(reinterpret_cast<const uint8_t*>(pSrcBuf), size);
|
|
TraceError("%s", contents.c_str());
|
|
}
|
|
#endif
|
|
|
|
return true;
|
|
/*
|
|
if (size > 0)
|
|
{
|
|
if (IsSecurityMode())
|
|
{
|
|
m_sendBufInputPos += TEA_Encrypt((DWORD *) (m_sendBuf + m_sendBufInputPos),
|
|
(DWORD *) (m_sendBuf + m_sendBufInputPos),
|
|
(const DWORD *) gs_szTeaKey,
|
|
size);
|
|
}
|
|
else
|
|
{
|
|
}
|
|
}
|
|
|
|
return __SendInternalBuffer();
|
|
*/
|
|
}
|
|
|
|
bool CNetworkStream::Peek(int len, void* pDestBuf)
|
|
{
|
|
return Peek(len, (char*)pDestBuf);
|
|
}
|
|
|
|
bool CNetworkStream::Recv(int len, void* pDestBuf)
|
|
{
|
|
return Recv(len, (char*)pDestBuf);
|
|
}
|
|
|
|
bool CNetworkStream::SendFlush(int len, const void* pSrcBuf)
|
|
{
|
|
if (!Send(len, pSrcBuf))
|
|
return false;
|
|
|
|
return __SendInternalBuffer();
|
|
}
|
|
|
|
bool CNetworkStream::Send(int len, const void* pSrcBuf)
|
|
{
|
|
return Send(len, (const char*)pSrcBuf);
|
|
}
|
|
|
|
bool CNetworkStream::IsOnline()
|
|
{
|
|
return m_isOnline;
|
|
}
|
|
|
|
void CNetworkStream::SetPacketSequenceMode(bool isOn)
|
|
{
|
|
m_bUseSequence = isOn;
|
|
}
|
|
|
|
bool CNetworkStream::SendSequence()
|
|
{
|
|
if (!m_bUseSequence)
|
|
return true;
|
|
|
|
BYTE bSeq = m_SequenceGenerator(UINT8_MAX + 1);
|
|
return Send(sizeof(BYTE), &bSeq);
|
|
}
|
|
|
|
uint8_t CNetworkStream::GetNextSequence()
|
|
{
|
|
return m_SequenceGenerator(UINT8_MAX + 1);
|
|
}
|
|
|
|
bool CNetworkStream::OnProcess()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void CNetworkStream::OnRemoteDisconnect()
|
|
{
|
|
}
|
|
|
|
void CNetworkStream::OnDisconnect()
|
|
{
|
|
}
|
|
|
|
void CNetworkStream::OnConnectSuccess()
|
|
{
|
|
Tracen("Succeed connecting.");
|
|
}
|
|
|
|
void CNetworkStream::OnConnectFailure()
|
|
{
|
|
Tracen("Failed to connect.");
|
|
}
|
|
|
|
//void CNetworkStream::OnCheckinSuccess()
|
|
//{
|
|
//}
|
|
|
|
//void CNetworkStream::OnCheckinFailure()
|
|
//{
|
|
//}
|
|
|
|
CNetworkStream::CNetworkStream()
|
|
{
|
|
m_sock = INVALID_SOCKET;
|
|
|
|
#ifndef _IMPROVED_PACKET_ENCRYPTION_
|
|
m_isSecurityMode = false;
|
|
#endif
|
|
m_isOnline = false;
|
|
m_connectLimitTime = 0;
|
|
|
|
m_recvTEABuf = NULL;
|
|
m_recvTEABufSize = 0;
|
|
m_recvTEABufInputPos = 0;
|
|
|
|
m_recvBuf = NULL;
|
|
m_recvBufSize = 0;
|
|
m_recvBufOutputPos = 0;
|
|
m_recvBufInputPos = 0;
|
|
|
|
m_sendTEABuf = NULL;
|
|
m_sendTEABuf = 0;
|
|
m_sendTEABufInputPos = 0;
|
|
|
|
m_sendBuf = NULL;
|
|
m_sendBufSize = 0;
|
|
m_sendBufOutputPos = 0;
|
|
m_sendBufInputPos = 0;
|
|
|
|
m_SequenceGenerator.seed(SEQUENCE_SEED);
|
|
m_bUseSequence = false;
|
|
}
|
|
|
|
CNetworkStream::~CNetworkStream()
|
|
{
|
|
Clear();
|
|
|
|
if (m_sendTEABuf)
|
|
{
|
|
delete [] m_sendTEABuf;
|
|
m_sendTEABuf=NULL;
|
|
}
|
|
|
|
if (m_recvTEABuf)
|
|
{
|
|
delete [] m_recvTEABuf;
|
|
m_recvTEABuf=NULL;
|
|
}
|
|
|
|
if (m_recvBuf)
|
|
{
|
|
delete [] m_recvBuf;
|
|
m_recvBuf=NULL;
|
|
}
|
|
|
|
if (m_sendBuf)
|
|
{
|
|
delete [] m_sendBuf;
|
|
m_sendBuf=NULL;
|
|
}
|
|
}
|
|
|
|
#ifdef _IMPROVED_PACKET_ENCRYPTION_
|
|
size_t CNetworkStream::Prepare(void* buffer, size_t* length)
|
|
{
|
|
return m_cipher.Prepare(buffer, length);
|
|
}
|
|
|
|
bool CNetworkStream::Activate(size_t agreed_length, const void* buffer, size_t length)
|
|
{
|
|
return m_cipher.Activate(true, agreed_length, buffer, length);
|
|
}
|
|
|
|
void CNetworkStream::ActivateCipher()
|
|
{
|
|
return m_cipher.set_activated(true);
|
|
}
|
|
|
|
// If cipher is active and there's unread data in buffer, decrypt it in-place
|
|
void CNetworkStream::DecryptAlreadyReceivedData()
|
|
{
|
|
if (!IsSecurityMode())
|
|
return;
|
|
|
|
const int unreadSize = m_recvBufInputPos - m_recvBufOutputPos;
|
|
if (unreadSize <= 0)
|
|
return;
|
|
|
|
m_cipher.Decrypt(m_recvBuf + m_recvBufOutputPos, unreadSize);
|
|
}
|
|
#endif // _IMPROVED_PACKET_ENCRYPTION_
|