Core/Packets: restore packet compression that got lost during the packet class porting

This commit is contained in:
Ovahlord
2019-08-29 17:15:18 +02:00
parent 706a9fea1a
commit 5657e61b24
6 changed files with 138 additions and 6 deletions

View File

@@ -1741,7 +1741,11 @@ inline std::string GetOpcodeNameForLoggingImpl(T id)
if (static_cast<uint16>(id) < NUM_OPCODE_HANDLERS)
{
if (OpcodeHandler const* handler = opcodeTable[id])
{
ss << handler->Name;
if (opcode & COMPRESSED_OPCODE_MASK)
ss << "_COMPRESSED";
}
else
ss << "UNKNOWN OPCODE";
}

View File

@@ -1380,8 +1380,11 @@ enum Opcodes : uint16
enum OpcodeMisc : uint16
{
NUM_OPCODE_HANDLERS = (0x7FFF + 1),
NULL_OPCODE = 0x0000
MAX_OPCODE = 0x7FFF,
NUM_OPCODE_HANDLERS = (MAX_OPCODE + 1),
UNKNOWN_OPCODE = 0xFFFF,
NULL_OPCODE = 0,
COMPRESSED_OPCODE_MASK = 0x8000
};
typedef Opcodes OpcodeClient;

View File

@@ -0,0 +1,108 @@
/*
* Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WorldPacket.h"
#include "Errors.h"
#include "Log.h"
#include "World.h"
#include <zlib.h>
//! Compresses packet in place
void WorldPacket::Compress(z_stream* compressionStream)
{
uint16 uncompressedOpcode = GetOpcode();
if (uncompressedOpcode & COMPRESSED_OPCODE_MASK)
{
TC_LOG_ERROR("network", "Packet with opcode 0x%04X is already compressed!", uncompressedOpcode);
return;
}
Opcodes opcode = Opcodes(uncompressedOpcode | COMPRESSED_OPCODE_MASK);
uint32 size = wpos();
uint32 destsize = compressBound(size);
std::vector<uint8> storage(destsize);
_compressionStream = compressionStream;
Compress(static_cast<void*>(&storage[0]), &destsize, static_cast<const void*>(contents()), size);
if (destsize == 0)
return;
clear();
reserve(destsize + sizeof(uint32));
*this << uint32(size);
append(&storage[0], destsize);
SetOpcode(opcode);
TC_LOG_INFO("network", "%s (len %u) successfully compressed to %04X (len %u)", GetOpcodeNameForLogging(Opcodes(uncompressedOpcode)).c_str(), size, opcode, destsize);
}
//! Compresses another packet and stores it in self (source left intact)
void WorldPacket::Compress(z_stream* compressionStream, WorldPacket const* source)
{
ASSERT(source != this);
uint16 uncompressedOpcode = source->GetOpcode();
if (uncompressedOpcode & COMPRESSED_OPCODE_MASK)
{
TC_LOG_ERROR("network", "Packet with opcode 0x%04X is already compressed!", uncompressedOpcode);
return;
}
Opcodes opcode = Opcodes(uncompressedOpcode | COMPRESSED_OPCODE_MASK);
uint32 size = source->size();
uint32 destsize = compressBound(size);
size_t sizePos = 0;
resize(destsize + sizeof(uint32));
_compressionStream = compressionStream;
Compress(static_cast<void*>(&_storage[0] + sizeof(uint32)), &destsize, static_cast<const void*>(source->contents()), size);
if (destsize == 0)
return;
put<uint32>(sizePos, size);
resize(destsize + sizeof(uint32));
SetOpcode(opcode);
TC_LOG_INFO("network", "%s (len %u) successfully compressed to %04X (len %u)", GetOpcodeNameForLogging(Opcodes(uncompressedOpcode)).c_str(), size, opcode, destsize);
}
void WorldPacket::Compress(void* dst, uint32 *dst_size, const void* src, int src_size)
{
_compressionStream->next_out = (Bytef*)dst;
_compressionStream->avail_out = *dst_size;
_compressionStream->next_in = (Bytef*)src;
_compressionStream->avail_in = (uInt)src_size;
int32 z_res = deflate(_compressionStream, Z_SYNC_FLUSH);
if (z_res != Z_OK)
{
TC_LOG_ERROR("network", "Can't compress packet (zlib: deflate) Error code: %i (%s, msg: %s)", z_res, zError(z_res), _compressionStream->msg);
*dst_size = 0;
return;
}
if (_compressionStream->avail_in != 0)
{
TC_LOG_ERROR("network", "Can't compress packet (zlib: deflate not greedy)");
*dst_size = 0;
return;
}
*dst_size -= _compressionStream->avail_out;
}

View File

@@ -24,11 +24,13 @@
#include "ByteBuffer.h"
#include <chrono>
struct z_stream_s;
class WorldPacket : public ByteBuffer
{
public:
// just container for later use
WorldPacket() : ByteBuffer(0), m_opcode(NULL_OPCODE)
WorldPacket() : ByteBuffer(0), m_opcode(UNKNOWN_OPCODE)
{
}
@@ -80,11 +82,17 @@ class WorldPacket : public ByteBuffer
uint16 GetOpcode() const { return m_opcode; }
void SetOpcode(uint16 opcode) { m_opcode = opcode; }
bool IsCompressed() const { return (m_opcode & COMPRESSED_OPCODE_MASK) != 0; }
void Compress(z_stream_s* compressionStream);
void Compress(z_stream_s* compressionStream, WorldPacket const* source);
std::chrono::steady_clock::time_point GetReceivedTime() const { return m_receivedTime; }
protected:
uint16 m_opcode;
void Compress(void* dst, uint32 *dst_size, const void* src, int src_size);
z_stream_s* _compressionStream;
std::chrono::steady_clock::time_point m_receivedTime; // only set for a specific set of opcodes, for performance reasons.
};

View File

@@ -222,10 +222,16 @@ void WorldSession::SendPacket(WorldPacket const* packet, bool forced /*= false*/
if (!m_Socket)
return;
ASSERT(packet->GetOpcode() != NULL_OPCODE);
if (!m_Socket)
if (packet->GetOpcode() == NULL_OPCODE)
{
TC_LOG_ERROR("network.opcode", "Prevented sending of NULL_OPCODE to %s", GetPlayerInfo().c_str());
return;
}
else if (packet->GetOpcode() == UNKNOWN_OPCODE)
{
TC_LOG_ERROR("network.opcode", "Prevented sending of UNKNOWN_OPCODE to %s", GetPlayerInfo().c_str());
return;
}
if (!forced)
{

View File

@@ -104,6 +104,9 @@ bool WorldSocket::Update()
MessageBuffer buffer(_sendBufferSize);
while (_bufferQueue.Dequeue(queued))
{
if (_worldSession && queued->size() > 0x400 && !queued->IsCompressed())
queued->Compress(_worldSession->GetCompressionStream());
ServerPktHeader header(queued->size() + 2, queued->GetOpcode());
if (queued->NeedsEncryption())
_authCrypt.EncryptSend(header.header, header.getHeaderLength());