mirror of
https://github.com/edubart/otclient.git
synced 2025-10-16 04:24:54 +02:00
support for protocol 810
* change in protocol/network classes to make compatible with older protocols * use filestream for reading dat * add many ifdefs for multi-protocol support
This commit is contained in:
@@ -29,8 +29,28 @@ InputMessage::InputMessage()
|
||||
|
||||
void InputMessage::reset()
|
||||
{
|
||||
m_readPos = 0;
|
||||
m_messageSize = 2;
|
||||
m_messageSize = 0;
|
||||
m_readPos = MAX_HEADER_SIZE;
|
||||
m_headerPos = MAX_HEADER_SIZE;
|
||||
}
|
||||
|
||||
void InputMessage::setHeaderSize(uint16 size)
|
||||
{
|
||||
m_headerPos = MAX_HEADER_SIZE - size;
|
||||
m_readPos = m_headerPos;
|
||||
}
|
||||
|
||||
void InputMessage::fillBuffer(uint8 *buffer, uint16 size)
|
||||
{
|
||||
memcpy(m_buffer + m_readPos, buffer, size);
|
||||
m_messageSize += size;
|
||||
}
|
||||
|
||||
bool InputMessage::readChecksum()
|
||||
{
|
||||
uint32_t receivedCheck = getU32();
|
||||
uint32 checksum = Fw::getAdlerChecksum(m_buffer + m_readPos, getUnreadSize());
|
||||
return receivedCheck == checksum;
|
||||
}
|
||||
|
||||
uint8 InputMessage::getU8(bool peek)
|
||||
@@ -88,7 +108,7 @@ std::string InputMessage::getString()
|
||||
|
||||
bool InputMessage::canRead(int bytes)
|
||||
{
|
||||
if((m_readPos + bytes > m_messageSize) || (m_readPos + bytes > BUFFER_MAXSIZE))
|
||||
if((m_readPos - m_headerPos + bytes > m_messageSize) || (m_readPos + bytes > BUFFER_MAXSIZE))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@@ -31,34 +31,43 @@ class InputMessage
|
||||
public:
|
||||
enum {
|
||||
BUFFER_MAXSIZE = 16384,
|
||||
HEADER_POS = 0,
|
||||
HEADER_LENGTH = 2,
|
||||
CHECKSUM_POS = 2,
|
||||
CHECKSUM_LENGTH = 4,
|
||||
DATA_POS = 6,
|
||||
UNENCRYPTED_DATA_POS = 8
|
||||
MAX_HEADER_SIZE = 8,
|
||||
};
|
||||
|
||||
InputMessage();
|
||||
|
||||
void reset();
|
||||
|
||||
void fillBuffer(uint8 *buffer, uint16 size);
|
||||
uint16 readSize() { return getU16(); }
|
||||
bool readChecksum();
|
||||
|
||||
void setHeaderSize(uint16 size);
|
||||
void setMessageSize(uint16 size) { m_messageSize = size; }
|
||||
|
||||
void skipBytes(uint16 bytes) { m_readPos += bytes; }
|
||||
|
||||
uint8 getU8(bool peek = false);
|
||||
uint16 getU16(bool peek = false);
|
||||
uint32 getU32(bool peek = false);
|
||||
uint64 getU64(bool peek = false);
|
||||
std::string getString();
|
||||
|
||||
void skipBytes(uint16 bytes) { m_readPos += bytes; }
|
||||
uint8* getBuffer() { return m_buffer; }
|
||||
uint8* getReadBuffer() { return m_buffer + m_readPos; }
|
||||
uint8* getHeaderBuffer() { return m_buffer + m_headerPos; }
|
||||
uint8* getDataBuffer() { return m_buffer + MAX_HEADER_SIZE; }
|
||||
uint16 getHeaderSize() { return (MAX_HEADER_SIZE - m_headerPos); }
|
||||
uint16 getMessageSize() { return m_messageSize; }
|
||||
void setMessageSize(uint16 messageSize) { m_messageSize = messageSize; }
|
||||
bool eof() { return m_readPos >= m_messageSize; }
|
||||
int getReadSize() { return m_readPos - m_headerPos; }
|
||||
int getUnreadSize() { return m_messageSize - (m_readPos - m_headerPos); }
|
||||
|
||||
bool eof() { return (m_readPos - m_headerPos) >= m_messageSize; }
|
||||
|
||||
private:
|
||||
bool canRead(int bytes);
|
||||
void checkRead(int bytes);
|
||||
|
||||
uint16 m_headerPos;
|
||||
uint16 m_readPos;
|
||||
uint16 m_messageSize;
|
||||
uint8 m_buffer[BUFFER_MAXSIZE];
|
||||
|
@@ -29,7 +29,8 @@ OutputMessage::OutputMessage()
|
||||
|
||||
void OutputMessage::reset()
|
||||
{
|
||||
m_writePos = DATA_POS;
|
||||
m_writePos = MAX_HEADER_SIZE;
|
||||
m_headerPos = MAX_HEADER_SIZE;
|
||||
m_messageSize = 0;
|
||||
}
|
||||
|
||||
@@ -91,6 +92,23 @@ void OutputMessage::addPaddingBytes(int bytes, uint8 byte)
|
||||
m_messageSize += bytes;
|
||||
}
|
||||
|
||||
void OutputMessage::writeChecksum()
|
||||
{
|
||||
uint32 checksum = Fw::getAdlerChecksum(m_buffer + m_headerPos, m_messageSize);
|
||||
assert(m_headerPos - 4 >= 0);
|
||||
m_headerPos -= 4;
|
||||
Fw::writeLE32(m_buffer + m_headerPos, checksum);
|
||||
m_messageSize += 4;
|
||||
}
|
||||
|
||||
void OutputMessage::writeMessageSize()
|
||||
{
|
||||
assert(m_headerPos - 2 >= 0);
|
||||
m_headerPos -= 2;
|
||||
Fw::writeLE16(m_buffer + m_headerPos, m_messageSize);
|
||||
m_messageSize += 2;
|
||||
}
|
||||
|
||||
bool OutputMessage::canWrite(int bytes)
|
||||
{
|
||||
if(m_writePos + bytes > BUFFER_MAXSIZE)
|
||||
|
@@ -34,11 +34,7 @@ class OutputMessage : public LuaObject
|
||||
public:
|
||||
enum {
|
||||
BUFFER_MAXSIZE = 1024,
|
||||
HEADER_POS = 0,
|
||||
HEADER_LENGTH = 2,
|
||||
CHECKSUM_POS = 2,
|
||||
CHECKSUM_LENGTH = 4,
|
||||
DATA_POS = 6
|
||||
MAX_HEADER_SIZE = 8
|
||||
};
|
||||
|
||||
OutputMessage();
|
||||
@@ -53,15 +49,19 @@ public:
|
||||
void addString(const std::string& value);
|
||||
void addPaddingBytes(int bytes, uint8 byte = 0);
|
||||
|
||||
uint8* getBuffer() { return m_buffer; }
|
||||
uint8* getWriteBuffer() { return m_buffer + m_writePos; }
|
||||
uint8* getHeaderBuffer() { return m_buffer + m_headerPos; }
|
||||
uint8* getDataBuffer() { return m_buffer + MAX_HEADER_SIZE; }
|
||||
uint16 getMessageSize() { return m_messageSize; }
|
||||
void setMessageSize(uint16 messageSize) { m_messageSize = messageSize; }
|
||||
void setWritePos(uint16 writePos) { m_writePos = writePos; }
|
||||
|
||||
void writeChecksum();
|
||||
void writeMessageSize();
|
||||
|
||||
private:
|
||||
bool canWrite(int bytes);
|
||||
void checkWrite(int bytes);
|
||||
|
||||
uint16 m_headerPos;
|
||||
uint16 m_writePos;
|
||||
uint16 m_messageSize;
|
||||
uint8 m_buffer[BUFFER_MAXSIZE];
|
||||
|
@@ -69,40 +69,44 @@ void Protocol::send(OutputMessage& outputMessage)
|
||||
if(m_xteaEncryptionEnabled)
|
||||
xteaEncrypt(outputMessage);
|
||||
|
||||
// set checksum
|
||||
uint32 checksum = getAdlerChecksum(outputMessage.getBuffer() + OutputMessage::DATA_POS, outputMessage.getMessageSize());
|
||||
outputMessage.setWritePos(OutputMessage::CHECKSUM_POS);
|
||||
outputMessage.addU32(checksum);
|
||||
// write checksum
|
||||
if(m_checksumEnabled)
|
||||
outputMessage.writeChecksum();
|
||||
|
||||
// set size
|
||||
uint16 messageSize = outputMessage.getMessageSize();
|
||||
outputMessage.setWritePos(OutputMessage::HEADER_POS);
|
||||
outputMessage.addU16(messageSize);
|
||||
// wirte message size
|
||||
outputMessage.writeMessageSize();
|
||||
|
||||
// send
|
||||
if(m_connection)
|
||||
m_connection->write(outputMessage.getBuffer(), outputMessage.getMessageSize());
|
||||
m_connection->write(outputMessage.getHeaderBuffer(), outputMessage.getMessageSize());
|
||||
}
|
||||
|
||||
void Protocol::recv()
|
||||
{
|
||||
m_inputMessage.reset();
|
||||
|
||||
// first update message header size
|
||||
int headerSize = 2; // 2 bytes for message size
|
||||
if(m_checksumEnabled)
|
||||
headerSize += 4; // 4 bytes for checksum
|
||||
if(m_xteaEncryptionEnabled)
|
||||
headerSize += 2; // 2 bytes for XTEA encrypted message size
|
||||
m_inputMessage.setHeaderSize(headerSize);
|
||||
|
||||
// read the first 2 bytes which contain the message size
|
||||
if(m_connection)
|
||||
m_connection->read(InputMessage::HEADER_LENGTH, std::bind(&Protocol::internalRecvHeader, asProtocol(), std::placeholders::_1, std::placeholders::_2));
|
||||
m_connection->read(2, std::bind(&Protocol::internalRecvHeader, asProtocol(), std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
void Protocol::internalRecvHeader(uint8* buffer, uint16 size)
|
||||
{
|
||||
memcpy(m_inputMessage.getBuffer() + InputMessage::HEADER_POS, buffer, size);
|
||||
|
||||
// read message size
|
||||
uint16 dataSize = m_inputMessage.getU16();
|
||||
m_inputMessage.setMessageSize(dataSize);
|
||||
m_inputMessage.fillBuffer(buffer, size);
|
||||
uint16 remainingSize = m_inputMessage.readSize();
|
||||
|
||||
// schedule read for message data
|
||||
// read remaining message data
|
||||
if(m_connection)
|
||||
m_connection->read(dataSize, std::bind(&Protocol::internalRecvData, asProtocol(), std::placeholders::_1, std::placeholders::_2));
|
||||
m_connection->read(remainingSize, std::bind(&Protocol::internalRecvData, asProtocol(), std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
void Protocol::internalRecvData(uint8* buffer, uint16 size)
|
||||
@@ -113,19 +117,16 @@ void Protocol::internalRecvData(uint8* buffer, uint16 size)
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(m_inputMessage.getBuffer() + InputMessage::CHECKSUM_POS, buffer, size);
|
||||
m_inputMessage.fillBuffer(buffer, size);
|
||||
|
||||
if(m_checksumEnabled) {
|
||||
uint32 checksum = getAdlerChecksum(m_inputMessage.getBuffer() + InputMessage::DATA_POS, m_inputMessage.getMessageSize() - InputMessage::CHECKSUM_LENGTH);
|
||||
if(m_inputMessage.getU32() != checksum) {
|
||||
logTraceError("got a network message with invalid checksum");
|
||||
return;
|
||||
}
|
||||
if(m_checksumEnabled && !m_inputMessage.readChecksum()) {
|
||||
logTraceError("got a network message with invalid checksum");
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_xteaEncryptionEnabled) {
|
||||
if(!xteaDecrypt(m_inputMessage))
|
||||
return;
|
||||
if(m_xteaEncryptionEnabled && !xteaDecrypt(m_inputMessage)) {
|
||||
logTraceError("failed to decrypt message");
|
||||
return;
|
||||
}
|
||||
|
||||
onRecv(m_inputMessage);
|
||||
@@ -143,16 +144,16 @@ void Protocol::generateXteaKey()
|
||||
|
||||
bool Protocol::xteaDecrypt(InputMessage& inputMessage)
|
||||
{
|
||||
uint16 messageSize = inputMessage.getMessageSize() - InputMessage::CHECKSUM_LENGTH;
|
||||
if(messageSize % 8 != 0) {
|
||||
uint16 encryptedSize = inputMessage.getUnreadSize();
|
||||
if(encryptedSize % 8 != 0) {
|
||||
logTraceError("invalid encrypted network message");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 *buffer = (uint32*)(inputMessage.getBuffer() + InputMessage::DATA_POS);
|
||||
uint32 *buffer = (uint32*)(inputMessage.getReadBuffer());
|
||||
int readPos = 0;
|
||||
|
||||
while(readPos < messageSize/4) {
|
||||
while(readPos < encryptedSize/4) {
|
||||
uint32 v0 = buffer[readPos], v1 = buffer[readPos + 1];
|
||||
uint32 delta = 0x61C88647;
|
||||
uint32 sum = 0xC6EF3720;
|
||||
@@ -166,37 +167,32 @@ bool Protocol::xteaDecrypt(InputMessage& inputMessage)
|
||||
readPos = readPos + 2;
|
||||
}
|
||||
|
||||
int tmp = inputMessage.getU16();
|
||||
if(tmp > inputMessage.getMessageSize() - 4) {
|
||||
uint16 decryptedSize = inputMessage.getU16() + 2;
|
||||
int sizeDelta = decryptedSize - encryptedSize;
|
||||
if(sizeDelta > 0 || -sizeDelta > encryptedSize) {
|
||||
logTraceError("invalid decrypted a network message");
|
||||
return false;
|
||||
}
|
||||
|
||||
inputMessage.setMessageSize(tmp + InputMessage::UNENCRYPTED_DATA_POS);
|
||||
inputMessage.setMessageSize(inputMessage.getMessageSize() + sizeDelta);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Protocol::xteaEncrypt(OutputMessage& outputMessage)
|
||||
{
|
||||
uint16 messageLength = outputMessage.getMessageSize();
|
||||
|
||||
memmove(outputMessage.getBuffer() + OutputMessage::DATA_POS + 2, outputMessage.getBuffer() + OutputMessage::DATA_POS, messageLength);
|
||||
*(uint16*)(outputMessage.getBuffer() + OutputMessage::DATA_POS) = messageLength;
|
||||
|
||||
messageLength += 2;
|
||||
outputMessage.setMessageSize(messageLength);
|
||||
outputMessage.setWritePos(messageLength + OutputMessage::DATA_POS);
|
||||
outputMessage.writeMessageSize();
|
||||
uint16 encryptedSize = outputMessage.getMessageSize();
|
||||
|
||||
//add bytes until reach 8 multiple
|
||||
if((messageLength % 8) != 0) {
|
||||
uint16 n = 8 - (messageLength % 8);
|
||||
if((encryptedSize % 8) != 0) {
|
||||
uint16 n = 8 - (encryptedSize % 8);
|
||||
outputMessage.addPaddingBytes(n);
|
||||
messageLength += n;
|
||||
encryptedSize += n;
|
||||
}
|
||||
|
||||
int readPos = 0;
|
||||
uint32 *buffer = (uint32*)(outputMessage.getBuffer() + OutputMessage::DATA_POS);
|
||||
while(readPos < messageLength / 4) {
|
||||
uint32 *buffer = (uint32*)(outputMessage.getDataBuffer() - 2);
|
||||
while(readPos < encryptedSize / 4) {
|
||||
uint32 v0 = buffer[readPos], v1 = buffer[readPos + 1];
|
||||
uint32 delta = 0x61C88647;
|
||||
uint32 sum = 0;
|
||||
@@ -210,21 +206,3 @@ void Protocol::xteaEncrypt(OutputMessage& outputMessage)
|
||||
readPos = readPos + 2;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Protocol::getAdlerChecksum(uint8* buffer, uint16 size)
|
||||
{
|
||||
uint32 a = 1, b = 0;
|
||||
while (size > 0) {
|
||||
size_t tlen = size > 5552 ? 5552 : size;
|
||||
size -= tlen;
|
||||
do {
|
||||
a += *buffer++;
|
||||
b += a;
|
||||
} while (--tlen);
|
||||
|
||||
a %= 65521;
|
||||
b %= 65521;
|
||||
}
|
||||
|
||||
return (b << 16) | a;
|
||||
}
|
||||
|
@@ -64,7 +64,6 @@ protected:
|
||||
private:
|
||||
bool xteaDecrypt(InputMessage& inputMessage);
|
||||
void xteaEncrypt(OutputMessage& outputMessage);
|
||||
uint32 getAdlerChecksum(uint8* buffer, uint16 size);
|
||||
|
||||
bool m_checksumEnabled;
|
||||
bool m_xteaEncryptionEnabled;
|
||||
|
Reference in New Issue
Block a user