Skip to content

Commit 4577a88

Browse files
authored
Add packet compression (#4870)
1 parent 0adb986 commit 4577a88

7 files changed

+79
-23
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ endif ()
4949

5050
# Find packages.
5151
find_package(OpenSSL 3.0.0 REQUIRED COMPONENTS Crypto)
52+
find_package(ZLIB REQUIRED)
5253

5354
find_package(fmt 8.1.1 CONFIG)
5455
if (NOT fmt_FOUND)

src/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ target_link_libraries(tfslib PRIVATE
178178
fmt::fmt
179179
OpenSSL::Crypto
180180
pugixml::pugixml
181+
ZLIB::ZLIB
181182
${CMAKE_THREAD_LIBS_INIT}
182183
${LUA_LIBRARIES}
183184
${MYSQL_CLIENT_LIBS}

src/outputmessage.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ class OutputMessage : public NetworkMessage
2121

2222
void writeMessageLength() { add_header(info.length); }
2323

24-
void addCryptoHeader(checksumMode_t mode, uint32_t& sequence)
24+
void addCryptoHeader(checksumMode_t mode)
2525
{
2626
if (mode == CHECKSUM_ADLER) {
2727
add_header(adlerChecksum(&buffer[outputBufferStart], info.length));
2828
} else if (mode == CHECKSUM_SEQUENCE) {
29-
add_header(sequence++);
29+
add_header(getSequenceId());
3030
}
3131

3232
writeMessageLength();
@@ -48,6 +48,9 @@ class OutputMessage : public NetworkMessage
4848
info.position += msgLen;
4949
}
5050

51+
void setSequenceId(uint32_t sequence) { sequenceId = sequence; }
52+
uint32_t getSequenceId() const { return sequenceId; }
53+
5154
private:
5255
template <typename T>
5356
void add_header(T add)
@@ -60,6 +63,7 @@ class OutputMessage : public NetworkMessage
6063
}
6164

6265
MsgSize_t outputBufferStart = INITIAL_BUFFER_POSITION;
66+
uint32_t sequenceId;
6367
};
6468

6569
namespace tfs::net {

src/protocol.cpp

+41-1
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,20 @@ bool XTEA_decrypt(NetworkMessage& msg, const xtea::round_keys& key)
4646
void Protocol::onSendMessage(const OutputMessage_ptr& msg)
4747
{
4848
if (!rawMessages) {
49+
if (encryptionEnabled && checksumMode == CHECKSUM_SEQUENCE) {
50+
uint32_t compressionChecksum = 0;
51+
if (msg->getLength() >= 128 && deflateMessage(*msg)) {
52+
compressionChecksum = 0x80000000;
53+
}
54+
55+
msg->setSequenceId(compressionChecksum | getNextSequenceId());
56+
}
57+
4958
msg->writeMessageLength();
5059

5160
if (encryptionEnabled) {
5261
XTEA_encrypt(*msg, key);
53-
msg->addCryptoHeader(checksumMode, sequenceNumber);
62+
msg->addCryptoHeader(checksumMode);
5463
}
5564
}
5665
}
@@ -86,6 +95,37 @@ bool Protocol::RSA_decrypt(NetworkMessage& msg)
8695
return msg.getByte() == 0;
8796
}
8897

98+
bool Protocol::deflateMessage(OutputMessage& msg)
99+
{
100+
static thread_local std::vector<uint8_t> buffer(NETWORKMESSAGE_MAXSIZE);
101+
102+
zstream.next_in = msg.getOutputBuffer();
103+
zstream.avail_in = msg.getLength();
104+
zstream.next_out = buffer.data();
105+
zstream.avail_out = buffer.size();
106+
107+
const auto result = deflate(&zstream, Z_FINISH);
108+
if (result != Z_OK && result != Z_STREAM_END) {
109+
std::cout << "Error while deflating packet data error: " << (zstream.msg ? zstream.msg : "unknown")
110+
<< std::endl;
111+
return false;
112+
}
113+
114+
const auto size = zstream.total_out;
115+
deflateReset(&zstream);
116+
117+
if (size <= 0) {
118+
std::cout << "Deflated packet data had invalid size: " << size
119+
<< " error: " << (zstream.msg ? zstream.msg : "unknown") << std::endl;
120+
return false;
121+
}
122+
123+
msg.reset();
124+
msg.addBytes(reinterpret_cast<const char*>(buffer.data()), size);
125+
126+
return true;
127+
}
128+
89129
Connection::Address Protocol::getIP() const
90130
{
91131
if (auto connection = getConnection()) {

src/protocol.h

+22-1
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,17 @@
77
#include "connection.h"
88
#include "xtea.h"
99

10+
#include <zlib.h>
11+
1012
class Protocol : public std::enable_shared_from_this<Protocol>
1113
{
1214
public:
13-
explicit Protocol(Connection_ptr connection) : connection(connection) {}
15+
explicit Protocol(Connection_ptr connection) : connection(connection)
16+
{
17+
if (deflateInit2(&zstream, 6, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
18+
std::cout << "ZLIB initialization error: " << (zstream.msg ? zstream.msg : "unknown") << std::endl;
19+
}
20+
}
1421
virtual ~Protocol() = default;
1522

1623
// non-copyable
@@ -42,6 +49,16 @@ class Protocol : public std::enable_shared_from_this<Protocol>
4249
}
4350
}
4451

52+
uint32_t getNextSequenceId()
53+
{
54+
const auto sequence = ++sequenceNumber;
55+
if (sequenceNumber >= static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) {
56+
sequenceNumber = 0;
57+
}
58+
59+
return sequence;
60+
}
61+
4562
protected:
4663
static constexpr size_t RSA_BUFFER_LENGTH = 128;
4764

@@ -57,6 +74,8 @@ class Protocol : public std::enable_shared_from_this<Protocol>
5774

5875
static bool RSA_decrypt(NetworkMessage& msg);
5976

77+
bool deflateMessage(OutputMessage& msg);
78+
6079
void setRawMessages(bool value) { rawMessages = value; }
6180

6281
virtual void release() {}
@@ -72,6 +91,8 @@ class Protocol : public std::enable_shared_from_this<Protocol>
7291
bool encryptionEnabled = false;
7392
checksumMode_t checksumMode = CHECKSUM_ADLER;
7493
bool rawMessages = false;
94+
95+
z_stream zstream{};
7596
};
7697

7798
#endif // FS_PROTOCOL_H

src/protocolgame.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg)
383383
}
384384

385385
// Change packet verifying mode for QT clients
386-
if (version >= 1111 && operatingSystem >= CLIENTOS_QT_LINUX && operatingSystem < CLIENTOS_OTCLIENT_LINUX) {
386+
if (version >= 1111 && operatingSystem >= CLIENTOS_QT_LINUX && operatingSystem <= CLIENTOS_OTCLIENT_MAC) {
387387
setChecksumMode(CHECKSUM_SEQUENCE);
388388
}
389389

vcpkg.json

+7-18
Original file line numberDiff line numberDiff line change
@@ -14,38 +14,27 @@
1414
},
1515
"libmariadb",
1616
"openssl",
17-
"pugixml"
17+
"pugixml",
18+
"zlib"
1819
],
1920
"features": {
2021
"http": {
2122
"description": "Enable HTTP support",
22-
"dependencies": [
23-
"boost-beast",
24-
"boost-json"
25-
]
23+
"dependencies": ["boost-beast", "boost-json"]
2624
},
2725
"lua": {
2826
"description": "Use Lua instead of LuaJIT",
29-
"dependencies": [
30-
"lua"
31-
]
27+
"dependencies": ["lua"]
3228
},
3329
"luajit": {
3430
"description": "Use LuaJIT instead of Lua",
35-
"dependencies": [
36-
"luajit"
37-
]
31+
"dependencies": ["luajit"]
3832
},
3933
"unit-tests": {
4034
"description": "Build unit tests",
41-
"dependencies": [
42-
"boost-test"
43-
]
35+
"dependencies": ["boost-test"]
4436
}
4537
},
46-
"default-features": [
47-
"lua",
48-
"http"
49-
],
38+
"default-features": ["lua", "http"],
5039
"builtin-baseline": "215a2535590f1f63788ac9bd2ed58ad15e6afdff"
5140
}

0 commit comments

Comments
 (0)