diff options
author | Shauren <shauren.trinity@gmail.com> | 2014-10-31 22:36:43 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2014-10-31 22:36:43 +0100 |
commit | dd040c5992dcf23f7c4c35f2660370ab38b3e0f7 (patch) | |
tree | 1cab6b1d87fff8077a245562cccc9c98b7e36ff3 /src | |
parent | 7f7108815f5c9ef978b7a44432cac9fa19313d77 (diff) |
Core/NetworkIO: Fixed packet compression
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Object/Updates/UpdateData.cpp | 1 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Opcodes.h | 2 | ||||
-rw-r--r-- | src/server/game/Server/WorldPacket.cpp | 105 | ||||
-rw-r--r-- | src/server/game/Server/WorldPacket.h | 5 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.cpp | 33 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.h | 2 | ||||
-rw-r--r-- | src/server/game/Server/WorldSocket.cpp | 96 | ||||
-rw-r--r-- | src/server/game/Server/WorldSocket.h | 3 |
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; |