From ed09d4ae54b35930ca947f01b997cc8c79e3fa51 Mon Sep 17 00:00:00 2001 From: hg <4683435+hgtw@users.noreply.github.com> Date: Wed, 12 Feb 2020 20:05:28 -0500 Subject: [PATCH] Send packet uncompressed if zlib deflates to a larger size than input It's not guaranteed that deflate output will be smaller than the input. In some cases zlib-ng (Z_BEST_SPEED) compression is causing packets to increase in size and exceed m_max_packet_size. This results in the packets never being fully received by the client. Currently this is most reproducible in the spell_book section of the OP_PlayerProfile message. After using #scribespells this portion of the player profile has a lot of incrementing spellids which may be affecting the compression algorithm. The client never processes the player profile (MSG_SEND_PC) message and times out on zone entry. This isn't necessarily a bug with zlib-ng since it inflates back to the original input and normal zlib could do this too, but the current netcode doesn't handle this. --- common/net/daybreak_connection.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/common/net/daybreak_connection.cpp b/common/net/daybreak_connection.cpp index 8448049f5..bd0c39489 100644 --- a/common/net/daybreak_connection.cpp +++ b/common/net/daybreak_connection.cpp @@ -1047,12 +1047,14 @@ void EQ::Net::DaybreakConnection::Compress(Packet &p, size_t offset, size_t leng uint8_t new_buffer[2048] = { 0 }; uint8_t *buffer = (uint8_t*)p.Data() + offset; uint32_t new_length = 0; + bool send_uncompressed = true; if (length > 30) { new_length = Deflate(buffer, (uint32_t)length, new_buffer + 1, 2048) + 1; new_buffer[0] = 0x5a; + send_uncompressed = (new_length > length); } - else { + if (send_uncompressed) { memcpy(new_buffer + 1, buffer, length); new_buffer[0] = 0xa5; new_length = length + 1; @@ -1380,7 +1382,7 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id, } auto stream = &m_streams[stream_id]; - auto max_raw_size = m_max_packet_size - m_crc_bytes - DaybreakReliableHeader::size(); + auto max_raw_size = m_max_packet_size - m_crc_bytes - DaybreakReliableHeader::size() - 1; // -1 for compress flag size_t length = p.Length(); if (length > max_raw_size) { DaybreakReliableFragmentHeader first_header;