diff --git a/src/openrct2/network/NetworkBase.cpp b/src/openrct2/network/NetworkBase.cpp index ad9b50728a..54be0f9998 100644 --- a/src/openrct2/network/NetworkBase.cpp +++ b/src/openrct2/network/NetworkBase.cpp @@ -501,13 +501,13 @@ void NetworkBase::Flush() { if (GetMode() == NETWORK_MODE_CLIENT) { - _serverConnection->SendQueuedPackets(); + _serverConnection->SendQueuedData(); } else { for (auto& it : client_connection_list) { - it->SendQueuedPackets(); + it->SendQueuedData(); } } } @@ -2014,7 +2014,7 @@ void NetworkBase::ProcessDisconnectedClients() } // Make sure to send all remaining packets out before disconnecting. - connection->SendQueuedPackets(); + connection->SendQueuedData(); connection->Socket->Disconnect(); ServerClientDisconnected(connection); diff --git a/src/openrct2/network/NetworkConnection.cpp b/src/openrct2/network/NetworkConnection.cpp index a2fc31fed8..6cac60c46c 100644 --- a/src/openrct2/network/NetworkConnection.cpp +++ b/src/openrct2/network/NetworkConnection.cpp @@ -17,14 +17,18 @@ #include "Socket.h" #include "network.h" + #include + using namespace OpenRCT2; static constexpr size_t kNetworkDisconnectReasonBufSize = 256; -static constexpr size_t kNetworkBufferSize = 1024 * 64; // 64 KiB, maximum packet size. +static constexpr size_t kNetworkBufferSize = (1024 * 64) - 1; // 64 KiB, maximum packet size. #ifndef DEBUG static constexpr size_t kNetworkNoDataTimeout = 20; // Seconds. #endif +static_assert(kNetworkBufferSize <= std::numeric_limits::max(), "kNetworkBufferSize too big, uint16_t is max."); + NetworkConnection::NetworkConnection() noexcept { ResetLastPacketTime(); @@ -99,60 +103,43 @@ NetworkReadPacket NetworkConnection::ReadPacket() return NetworkReadPacket::MoreData; } -bool NetworkConnection::SendPacket(NetworkPacket& packet) +static sfl::small_vector serializePacket(const NetworkPacket& packet) { - auto header = packet.Header; - - std::vector buffer; - buffer.reserve(sizeof(header) + header.Size); - // NOTE: For compatibility reasons for the master server we need to add sizeof(Header.Id) to the size. // Previously the Id field was not part of the header rather part of the body. - header.Size += sizeof(header.Id); + const auto bodyLength = packet.Data.size() + sizeof(packet.Header.Id); + + Guard::Assert(bodyLength <= std::numeric_limits::max(), "Packet size too large"); + + auto header = packet.Header; + header.Size = static_cast(bodyLength); header.Size = Convert::HostToNetwork(header.Size); header.Id = ByteSwapBE(header.Id); + sfl::small_vector buffer; + buffer.reserve(sizeof(header) + packet.Data.size()); + buffer.insert(buffer.end(), reinterpret_cast(&header), reinterpret_cast(&header) + sizeof(header)); buffer.insert(buffer.end(), packet.Data.begin(), packet.Data.end()); - size_t bufferSize = buffer.size() - packet.BytesTransferred; - size_t sent = Socket->SendData(buffer.data() + packet.BytesTransferred, bufferSize); - if (sent > 0) - { - packet.BytesTransferred += sent; - } - - bool sendComplete = packet.BytesTransferred == buffer.size(); - if (sendComplete) - { - RecordPacketStats(packet, true); - } - return sendComplete; + return buffer; } -void NetworkConnection::QueuePacket(NetworkPacket&& packet, bool front) +void NetworkConnection::QueuePacket(const NetworkPacket& packet, bool front) { if (AuthStatus == NetworkAuth::Ok || !packet.CommandRequiresAuth()) { - packet.Header.Size = static_cast(packet.Data.size()); + const auto payload = serializePacket(packet); if (front) { - // If the first packet was already partially sent add new packet to second position - if (!_outboundPackets.empty() && _outboundPackets.front().BytesTransferred > 0) - { - auto it = _outboundPackets.begin(); - it++; // Second position - _outboundPackets.insert(it, std::move(packet)); - } - else - { - _outboundPackets.push_front(std::move(packet)); - } + _outboundBuffer.insert(_outboundBuffer.begin(), payload.begin(), payload.end()); } else { - _outboundPackets.push_back(std::move(packet)); + _outboundBuffer.insert(_outboundBuffer.end(), payload.begin(), payload.end()); } + + RecordPacketStats(packet, true); } } @@ -166,11 +153,18 @@ bool NetworkConnection::IsValid() const return !ShouldDisconnect && Socket->GetStatus() == SocketStatus::Connected; } -void NetworkConnection::SendQueuedPackets() +void NetworkConnection::SendQueuedData() { - while (!_outboundPackets.empty() && SendPacket(_outboundPackets.front())) + if (_outboundBuffer.empty()) { - _outboundPackets.pop_front(); + return; + } + + const auto bytesSent = Socket->SendData(_outboundBuffer.data(), _outboundBuffer.size()); + + if (bytesSent > 0) + { + _outboundBuffer.erase(_outboundBuffer.begin(), _outboundBuffer.begin() + bytesSent); } } diff --git a/src/openrct2/network/NetworkConnection.h b/src/openrct2/network/NetworkConnection.h index c5fb549b53..fa927ddb3f 100644 --- a/src/openrct2/network/NetworkConnection.h +++ b/src/openrct2/network/NetworkConnection.h @@ -16,7 +16,6 @@ #include "NetworkTypes.h" #include "Socket.h" - #include #include #include #include @@ -41,19 +40,14 @@ public: NetworkConnection() noexcept; NetworkReadPacket ReadPacket(); - void QueuePacket(NetworkPacket&& packet, bool front = false); - void QueuePacket(const NetworkPacket& packet, bool front = false) - { - auto copy = packet; - return QueuePacket(std::move(copy), front); - } + void QueuePacket(const NetworkPacket& packet, bool front = false); // This will not immediately disconnect the client. The disconnect // will happen post-tick. void Disconnect() noexcept; bool IsValid() const; - void SendQueuedPackets(); + void SendQueuedData(); void ResetLastPacketTime() noexcept; bool ReceivedPacketRecently() const noexcept; @@ -62,12 +56,11 @@ public: void SetLastDisconnectReason(const StringId string_id, void* args = nullptr); private: - std::deque _outboundPackets; + std::vector _outboundBuffer; uint32_t _lastPacketTime = 0; std::string _lastDisconnectReason; void RecordPacketStats(const NetworkPacket& packet, bool sending); - bool SendPacket(NetworkPacket& packet); }; #endif // DISABLE_NETWORK diff --git a/src/openrct2/network/NetworkPacket.h b/src/openrct2/network/NetworkPacket.h index 20f4a7cd87..a262fc1761 100644 --- a/src/openrct2/network/NetworkPacket.h +++ b/src/openrct2/network/NetworkPacket.h @@ -13,6 +13,7 @@ #include "NetworkTypes.h" #include +#include #include #pragma pack(push, 1) @@ -76,7 +77,7 @@ struct NetworkPacket final public: PacketHeader Header{}; - std::vector Data; + sfl::small_vector Data; size_t BytesTransferred = 0; size_t BytesRead = 0; };