diff --git a/include/Common.h b/include/Common.h index 4960077..488b8d1 100644 --- a/include/Common.h +++ b/include/Common.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -262,57 +263,8 @@ void RegisterThread(const std::string& str); void LogChatMessage(const std::string& name, int id, const std::string& msg); -#define Biggest 30000 - -template -inline T Comp(const T& Data) { - std::array C {}; - // obsolete - C.fill(0); - z_stream defstream; - defstream.zalloc = nullptr; - defstream.zfree = nullptr; - defstream.opaque = nullptr; - defstream.avail_in = uInt(Data.size()); - defstream.next_in = const_cast(reinterpret_cast(&Data[0])); - defstream.avail_out = Biggest; - defstream.next_out = reinterpret_cast(C.data()); - deflateInit(&defstream, Z_BEST_COMPRESSION); - deflate(&defstream, Z_SYNC_FLUSH); - deflate(&defstream, Z_FINISH); - deflateEnd(&defstream); - size_t TotalOut = defstream.total_out; - T Ret; - Ret.resize(TotalOut); - std::fill(Ret.begin(), Ret.end(), 0); - std::copy_n(C.begin(), TotalOut, Ret.begin()); - return Ret; -} - -template -inline T DeComp(const T& Compressed) { - std::array C {}; - // not needed - C.fill(0); - z_stream infstream; - infstream.zalloc = nullptr; - infstream.zfree = nullptr; - infstream.opaque = nullptr; - infstream.avail_in = Biggest; - infstream.next_in = const_cast(reinterpret_cast(&Compressed[0])); - infstream.avail_out = Biggest; - infstream.next_out = const_cast(reinterpret_cast(C.data())); - inflateInit(&infstream); - inflate(&infstream, Z_SYNC_FLUSH); - inflate(&infstream, Z_FINISH); - inflateEnd(&infstream); - size_t TotalOut = infstream.total_out; - T Ret; - Ret.resize(TotalOut); - std::fill(Ret.begin(), Ret.end(), 0); - std::copy_n(C.begin(), TotalOut, Ret.begin()); - return Ret; -} +std::vector Comp(std::span input); +std::vector DeComp(std::span input); std::string GetPlatformAgnosticErrorString(); #define S_DSN SU_RAW diff --git a/src/Common.cpp b/src/Common.cpp index 4988fc4..024e701 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -383,3 +384,51 @@ void SplitString(const std::string& str, const char delim, std::vector DeComp(std::span input) { + beammp_debugf("got {} bytes of input data", input.size()); + + std::vector output_buffer(std::min(input.size() * 5, 15 * 1024 * 1024)); + + uLongf output_size = output_buffer.size(); + + while (true) { + int res = uncompress( + reinterpret_cast(output_buffer.data()), + &output_size, + reinterpret_cast(input.data()), + static_cast(input.size())); + if (res == Z_BUF_ERROR) { + if (output_buffer.size() > 30 * 1024 * 1024) { + throw std::runtime_error("decompressed packet size of 30 MB exceeded"); + } + beammp_warn("zlib uncompress() failed, trying with 2x buffer size of " + std::to_string(output_buffer.size() * 2)); + output_buffer.resize(output_buffer.size() * 2); + output_size = output_buffer.size(); + } else if (res != Z_OK) { + beammp_error("zlib uncompress() failed: " + std::to_string(res)); + throw std::runtime_error("zlib uncompress() failed"); + } else if (res == Z_OK) { + break; + } + } + output_buffer.resize(output_size); + return output_buffer; +} + +std::vector Comp(std::span input) { + auto max_size = compressBound(input.size()); + std::vector output(max_size); + uLongf output_size = output.size(); + int res = compress( + reinterpret_cast(output.data()), + &output_size, + reinterpret_cast(input.data()), + static_cast(input.size())); + if (res != Z_OK) { + beammp_error("zlib compress() failed: " + std::to_string(res)); + throw std::runtime_error("zlib compress() failed"); + } + beammp_debug("zlib compressed " + std::to_string(input.size()) + " B to " + std::to_string(output_size) + " B"); + output.resize(output_size); + return output; +} diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index ddecf69..da510cc 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -28,6 +28,7 @@ #include #include #include +#include typedef boost::asio::detail::socket_option::integer rcv_timeout_option; @@ -866,7 +867,7 @@ bool TNetwork::SendLarge(TClient& c, std::vector Data, bool isSync) { bool TNetwork::Respond(TClient& c, const std::vector& MSG, bool Rel, bool isSync) { char C = MSG.at(0); - if (Rel || C == 'W' || C == 'Y' || C == 'V' || C == 'E') { + if (Rel || C == 'W' || C == 'Y' || C == 'V' || C == 'E' || compressBound(MSG.size()) > 1024) { if (C == 'O' || C == 'T' || MSG.size() > 1000) { return SendLarge(c, MSG, isSync); } else { @@ -949,7 +950,7 @@ void TNetwork::SendToAll(TClient* c, const std::vector& Data, bool Self } if (Self || Client.get() != c) { if (Client->IsSynced() || Client->IsSyncing()) { - if (Rel || C == 'W' || C == 'Y' || C == 'V' || C == 'E') { + if (Rel || C == 'W' || C == 'Y' || C == 'V' || C == 'E' || compressBound(Data.size()) > 1024) { if (C == 'O' || C == 'T' || Data.size() > 1000) { if (Data.size() > 400) { auto CompressedData = Data; diff --git a/src/TServer.cpp b/src/TServer.cpp index 215ae0a..22e7c53 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -392,13 +392,21 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ } return; } - case 't': + case 't': { beammp_trace(std::string(("got 'Ot' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); + auto MaybePidVid = GetPidVid(Data.substr(0, Data.find(':', 1))); + if (MaybePidVid) { + std::tie(PID, VID) = MaybePidVid.value(); + } + if (PID != -1 && VID != -1 && PID == c.GetID()) { + Network.SendToAll(&c, StringToVector(Packet), false, true); + } + return; + } + case 'm': { Network.SendToAll(&c, StringToVector(Packet), false, true); return; - case 'm': - Network.SendToAll(&c, StringToVector(Packet), true, true); - return; + } default: beammp_trace(std::string(("possibly not implemented: '") + Packet + ("' (") + std::to_string(Packet.size()) + (")"))); return;