aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2014-10-31 22:36:43 +0100
committerShauren <shauren.trinity@gmail.com>2014-10-31 22:36:43 +0100
commitdd040c5992dcf23f7c4c35f2660370ab38b3e0f7 (patch)
tree1cab6b1d87fff8077a245562cccc9c98b7e36ff3 /src
parent7f7108815f5c9ef978b7a44432cac9fa19313d77 (diff)
Core/NetworkIO: Fixed packet compression
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Object/Updates/UpdateData.cpp1
-rw-r--r--src/server/game/Server/Protocol/Opcodes.h2
-rw-r--r--src/server/game/Server/WorldPacket.cpp105
-rw-r--r--src/server/game/Server/WorldPacket.h5
-rw-r--r--src/server/game/Server/WorldSession.cpp33
-rw-r--r--src/server/game/Server/WorldSession.h2
-rw-r--r--src/server/game/Server/WorldSocket.cpp96
-rw-r--r--src/server/game/Server/WorldSocket.h3
8 files changed, 106 insertions, 141 deletions
diff --git a/src/server/game/Entities/Object/Updates/UpdateData.cpp b/src/server/game/Entities/Object/Updates/UpdateData.cpp
index eaecbdac3c1..db911dfa267 100644
--- a/src/server/game/Entities/Object/Updates/UpdateData.cpp
+++ b/src/server/game/Entities/Object/Updates/UpdateData.cpp
@@ -23,7 +23,6 @@
#include "Log.h"
#include "Opcodes.h"
#include "World.h"
-#include "zlib.h"
UpdateData::UpdateData(uint16 map) : m_map(map), m_blockCount(0) { }
diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h
index bc542f2bdc3..020a251de0e 100644
--- a/src/server/game/Server/Protocol/Opcodes.h
+++ b/src/server/game/Server/Protocol/Opcodes.h
@@ -197,7 +197,7 @@ enum OpcodeClient : uint32
CMSG_EJECT_PASSENGER = 0x0000,
CMSG_EMOTE = 0x0000,
CMSG_ENABLETAXI = 0x0000,
- CMSG_ENABLE_NAGLE = 0x0000,
+ CMSG_ENABLE_NAGLE = 0x0460,
CMSG_EQUIPMENT_SET_DELETE = 0x0000,
CMSG_EQUIPMENT_SET_SAVE = 0x1B54,
CMSG_EQUIPMENT_SET_USE = 0x0000,
diff --git a/src/server/game/Server/WorldPacket.cpp b/src/server/game/Server/WorldPacket.cpp
deleted file mode 100644
index ab2c0b089e2..00000000000
--- a/src/server/game/Server/WorldPacket.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2008-2014 TrinityCore <http://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 <zlib.h>
-#include "WorldPacket.h"
-#include "World.h"
-
-//! Compresses packet in place
-void WorldPacket::Compress(z_stream* compressionStream)
-{
- OpcodeServer uncompressedOpcode = static_cast<OpcodeServer>(GetOpcode());
- if (uncompressedOpcode == SMSG_COMPRESSED_PACKET)
- {
- TC_LOG_ERROR("network", "Packet with opcode 0x%04X is already compressed!", uncompressedOpcode);
- return;
- }
-
- 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) * 2);
- *this << uint32(uncompressedOpcode);
- *this << uint32(size);
- append(&storage[0], destsize);
- SetOpcode(SMSG_COMPRESSED_PACKET);
- TC_LOG_INFO("network", "%s (len %u) successfully compressed to len %u", GetOpcodeNameForLogging(uncompressedOpcode).c_str(), size, destsize);
-}
-
-//! Compresses another packet and stores it in self (source left intact)
-void WorldPacket::Compress(z_stream* compressionStream, WorldPacket const* source)
-{
- ASSERT(source != this);
-
- OpcodeServer uncompressedOpcode = static_cast<OpcodeServer>(source->GetOpcode());
- if (uncompressedOpcode == SMSG_COMPRESSED_PACKET)
- {
- TC_LOG_ERROR("network", "Packet with opcode 0x%04X is already compressed!", uncompressedOpcode);
- return;
- }
-
- uint32 size = source->size();
- uint32 destsize = compressBound(size);
-
- resize(destsize + sizeof(uint32) * 2);
-
- _compressionStream = compressionStream;
- Compress(static_cast<void*>(&_storage[0] + sizeof(uint32) * 2), &destsize, static_cast<const void*>(source->contents()), size);
- if (destsize == 0)
- return;
-
- put<uint32>(0, uncompressedOpcode);
- put<uint32>(4, size);
- resize(destsize + sizeof(uint32));
-
- SetOpcode(SMSG_COMPRESSED_PACKET);
-
- TC_LOG_INFO("network", "%s (len %u) successfully compressed to len %u", GetOpcodeNameForLogging(uncompressedOpcode).c_str(), size, 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;
-}
diff --git a/src/server/game/Server/WorldPacket.h b/src/server/game/Server/WorldPacket.h
index 9e29026ba05..d04679adbd4 100644
--- a/src/server/game/Server/WorldPacket.h
+++ b/src/server/game/Server/WorldPacket.h
@@ -65,14 +65,9 @@ class WorldPacket : public ByteBuffer
uint32 GetOpcode() const { return m_opcode; }
void SetOpcode(uint32 opcode) { m_opcode = opcode; }
- bool IsCompressed() const { return m_opcode == SMSG_COMPRESSED_PACKET; }
- void Compress(z_stream_s* compressionStream);
- void Compress(z_stream_s* compressionStream, WorldPacket const* source);
protected:
uint32 m_opcode;
- void Compress(void* dst, uint32 *dst_size, const void* src, int src_size);
- z_stream_s* _compressionStream;
};
#endif
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 9e22e294a0a..703a867ca11 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -147,7 +147,7 @@ WorldSession::WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr
_compressionStream->opaque = (voidpf)NULL;
_compressionStream->avail_in = 0;
_compressionStream->next_in = NULL;
- int32 z_res = deflateInit(_compressionStream, sWorld->getIntConfig(CONFIG_COMPRESSION));
+ int32 z_res = deflateInit2(_compressionStream, sWorld->getIntConfig(CONFIG_COMPRESSION), Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
if (z_res != Z_OK)
TC_LOG_ERROR("network", "Can't initialize packet compression (zlib: deflateInit) Error code: %i (%s)", z_res, zError(z_res));
}
@@ -267,6 +267,37 @@ void WorldSession::SendPacket(WorldPacket* packet, bool forced /*= false*/)
m_Socket->SendPacket(*packet);
}
+uint32 WorldSession::CompressPacket(uint8* buffer, WorldPacket const& packet)
+{
+ uint32 opcode = packet.GetOpcode();
+ uint32 bufferSize = deflateBound(_compressionStream, packet.size() + sizeof(opcode));
+
+ _compressionStream->next_out = buffer;
+ _compressionStream->avail_out = bufferSize;
+ _compressionStream->next_in = (Bytef*)&opcode;
+ _compressionStream->avail_in = sizeof(uint32);
+
+ int32 z_res = deflate(_compressionStream, Z_BLOCK);
+ if (z_res != Z_OK)
+ {
+ TC_LOG_ERROR("network", "Can't compress packet opcode (zlib: deflate) Error code: %i (%s, msg: %s)", z_res, zError(z_res), _compressionStream->msg);
+ return 0;
+ }
+
+ _compressionStream->next_in = (Bytef*)packet.contents();
+ _compressionStream->avail_in = packet.size();
+
+ z_res = deflate(_compressionStream, Z_SYNC_FLUSH);
+ if (z_res != Z_OK)
+ {
+ TC_LOG_ERROR("network", "Can't compress packet data (zlib: deflate) Error code: %i (%s, msg: %s)", z_res, zError(z_res), _compressionStream->msg);
+ return 0;
+ }
+
+
+ return bufferSize - _compressionStream->avail_out;
+}
+
/// Add an incoming packet to the queue
void WorldSession::QueuePacket(WorldPacket* new_packet)
{
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index ef29f0da7e6..5b707809cde 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -273,6 +273,8 @@ class WorldSession
bool IsAddonRegistered(const std::string& prefix) const;
void SendPacket(WorldPacket* packet, bool forced = false);
+ uint32 CompressPacket(uint8* buffer, WorldPacket const& packet);
+
void SendNotification(const char *format, ...) ATTR_PRINTF(2, 3);
void SendNotification(uint32 string_id, ...);
void SendPetNameInvalid(uint32 error, std::string const& name, DeclinedName *declinedName);
diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp
index 25ed950a37c..e3fcd124881 100644
--- a/src/server/game/Server/WorldSocket.cpp
+++ b/src/server/game/Server/WorldSocket.cpp
@@ -25,8 +25,20 @@
#include "SHA1.h"
#include "PacketLog.h"
#include "BattlenetAccountMgr.h"
+#include <zlib.h>
#include <memory>
+#pragma pack(push, 1)
+
+struct CompressedWorldPacket
+{
+ uint32 UncompressedSize;
+ uint32 UncompressedAdler;
+ uint32 CompressedAdler;
+};
+
+#pragma pack(pop)
+
using boost::asio::ip::tcp;
std::string const WorldSocket::ServerConnectionInitialize("WORLD OF WARCRAFT CONNECTION - SERVER TO CLIENT");
@@ -220,6 +232,7 @@ bool WorldSocket::ReadDataHandler()
TC_LOG_DEBUG("network", "%s", opcodeName.c_str());
sScriptMgr->OnPacketReceive(_worldSession, packet);
break;
+ */
case CMSG_LOG_DISCONNECT:
packet.rfinish(); // contains uint32 disconnectReason;
TC_LOG_DEBUG("network", "%s", opcodeName.c_str());
@@ -233,7 +246,6 @@ bool WorldSocket::ReadDataHandler()
_worldSession->HandleEnableNagleAlgorithm();
break;
}
- */
default:
{
if (!_worldSession)
@@ -285,50 +297,80 @@ bool WorldSocket::ReadDataHandler()
return true;
}
-void WorldSocket::SendPacket(WorldPacket& packet)
+void WorldSocket::WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& buffer)
{
- if (!IsOpen())
- return;
+ ServerPktHeader header;
+ uint32 sizeOfHeader = SizeOfServerHeader[_authCrypt.IsInitialized()];
+ uint32 opcode = packet.GetOpcode();
+ uint32 packetSize = packet.size();
- if (sPacketLog->CanLogPacket())
- sPacketLog->LogPacket(packet, SERVER_TO_CLIENT, GetRemoteIpAddress(), GetRemotePort());
+ // Reserve space for buffer
+ uint8* headerPos = buffer.GetWritePointer();
+ buffer.WriteCompleted(sizeOfHeader);
- if (_worldSession && packet.size() > 0x400 && !packet.IsCompressed())
- packet.Compress(_worldSession->GetCompressionStream());
+ if (packetSize > 0x400 && _worldSession)
+ {
+ CompressedWorldPacket cmp;
+ cmp.UncompressedSize = packetSize + 4;
+ cmp.UncompressedAdler = adler32(adler32(0x9827D8F1, (Bytef*)&opcode, 4), packet.contents(), packetSize);
- TC_LOG_TRACE("network.opcode", "S->C: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), GetOpcodeNameForLogging(static_cast<OpcodeServer>(packet.GetOpcode())).c_str());
+ // Reserve space for compression info - uncompressed size and checksums
+ uint8* compressionInfo = buffer.GetWritePointer();
+ buffer.WriteCompleted(sizeof(CompressedWorldPacket));
- std::unique_lock<std::mutex> guard(_writeLock);
+ uint32 compressedSize = _worldSession->CompressPacket(buffer.GetWritePointer(), packet);
+
+ cmp.CompressedAdler = adler32(0x9827D8F1, buffer.GetWritePointer(), compressedSize);
+
+ memcpy(compressionInfo, &cmp, sizeof(CompressedWorldPacket));
+ buffer.WriteCompleted(compressedSize);
+ packetSize = compressedSize + sizeof(CompressedWorldPacket);
+
+ opcode = SMSG_COMPRESSED_PACKET;
+ }
+ else if (!packet.empty())
+ buffer.Write(packet.contents(), packet.size());
- ServerPktHeader header;
- uint32 sizeOfHeader = SizeOfServerHeader[_authCrypt.IsInitialized()];
if (_authCrypt.IsInitialized())
{
- header.Normal.Size = packet.size();
- header.Normal.Command = packet.GetOpcode();
+ header.Normal.Size = packetSize;
+ header.Normal.Command = opcode;
_authCrypt.EncryptSend((uint8*)&header, sizeOfHeader);
}
else
{
- header.Setup.Size = packet.size() + 4;
- header.Setup.Command = packet.GetOpcode();
+ header.Setup.Size = packetSize + 4;
+ header.Setup.Command = opcode;
}
+ memcpy(headerPos, &header, sizeOfHeader);
+}
+
+void WorldSocket::SendPacket(WorldPacket const& packet)
+{
+ if (!IsOpen())
+ return;
+
+ if (sPacketLog->CanLogPacket())
+ sPacketLog->LogPacket(packet, SERVER_TO_CLIENT, GetRemoteIpAddress(), GetRemotePort());
+
+ TC_LOG_TRACE("network.opcode", "S->C: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), GetOpcodeNameForLogging(static_cast<OpcodeServer>(packet.GetOpcode())).c_str());
+
+ uint32 packetSize = packet.size();
+ uint32 sizeOfHeader = SizeOfServerHeader[_authCrypt.IsInitialized()];
+ if (packetSize > 0x400 && _worldSession)
+ packetSize = compressBound(packetSize) + sizeof(CompressedWorldPacket);
+
+ std::unique_lock<std::mutex> guard(_writeLock);
+
#ifndef TC_SOCKET_USE_IOCP
- if (_writeQueue.empty() && _writeBuffer.GetRemainingSpace() >= sizeOfHeader + packet.size())
- {
- _writeBuffer.Write((uint8*)&header, sizeOfHeader);
- if (!packet.empty())
- _writeBuffer.Write(packet.contents(), packet.size());
- }
+ if (_writeQueue.empty() && _writeBuffer.GetRemainingSpace() >= sizeOfHeader + packetSize)
+ WritePacketToBuffer(packet, _writeBuffer);
else
#endif
{
- MessageBuffer buffer(sizeOfHeader + packet.size());
- buffer.Write((uint8*)&header, sizeOfHeader);
- if (!packet.empty())
- buffer.Write(packet.contents(), packet.size());
-
+ MessageBuffer buffer(sizeOfHeader + packetSize);
+ WritePacketToBuffer(packet, buffer);
QueuePacket(std::move(buffer), guard);
}
}
diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h
index 0517ebcce91..e0dad0a43a1 100644
--- a/src/server/game/Server/WorldSocket.h
+++ b/src/server/game/Server/WorldSocket.h
@@ -73,7 +73,8 @@ public:
void Start() override;
- void SendPacket(WorldPacket& packet);
+ void SendPacket(WorldPacket const& packet);
+ void WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& buffer);
protected:
void ReadHandler() override;