From f1ec753ca30c4eced44342c30f46016d12dd195c Mon Sep 17 00:00:00 2001 From: Katharine Chui Date: Tue, 28 Apr 2026 12:26:20 +0200 Subject: [PATCH 1/4] handle incomplete MSG_WAITALL during tcp receive --- src/Network/VehicleEvent.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Network/VehicleEvent.cpp b/src/Network/VehicleEvent.cpp index dcbb41e5..f6038de4 100644 --- a/src/Network/VehicleEvent.cpp +++ b/src/Network/VehicleEvent.cpp @@ -75,6 +75,23 @@ void TCPSend(const std::string& Data, uint64_t Sock) { } while (Sent < Size); } +int RecvWaitAll(int sockfd, char *buf, int len) { + // handle MSG_WAITALL not actually filling the whole buffer + // happens frequently in wine, and can also happen natively when the OS pauses the execution for various reasons + int offset = 0; + while (offset < len) { + int recv_status = recv(sockfd, &buf[offset], len - offset, MSG_WAITALL); + if (recv_status == 0) { + return 0; + } + if (recv_status == -1) { + return -1; + } + offset += recv_status; + } + return offset; +} + std::string TCPRcv(SOCKET Sock) { if (Sock == -1) { Terminate = true; @@ -84,7 +101,7 @@ std::string TCPRcv(SOCKET Sock) { int32_t Header; int Temp; std::vector Data(sizeof(Header)); - Temp = recv(Sock, Data.data(), sizeof(Header), MSG_WAITALL); + Temp = RecvWaitAll(Sock, Data.data(), sizeof(Header)); if (!CheckBytes(Temp)) { UUl("Socket Closed Code 3"); return ""; @@ -97,7 +114,7 @@ std::string TCPRcv(SOCKET Sock) { } Data.resize(Header, 0); - Temp = recv(Sock, Data.data(), Header, MSG_WAITALL); + Temp = RecvWaitAll(Sock, Data.data(), Header); if (!CheckBytes(Temp)) { UUl("Socket Closed Code 5"); return ""; From 809080c9aa14474f1ea2a86804e53855ba68a8b2 Mon Sep 17 00:00:00 2001 From: Katharine Chui Date: Thu, 30 Apr 2026 19:51:13 +0200 Subject: [PATCH 2/4] use RecvWaitAll outside of VehicleEvent.cpp as well --- include/Network/network.hpp | 1 + src/Network/Core.cpp | 4 ++-- src/Network/Resources.cpp | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/Network/network.hpp b/include/Network/network.hpp index f58bdad4..94e4fb52 100644 --- a/include/Network/network.hpp +++ b/include/Network/network.hpp @@ -56,3 +56,4 @@ void UDPClientMain(const std::string& IP, int Port); void TCPGameServer(const std::string& IP, int Port); bool SecurityWarning(); void CoreSend(std::string data); +int RecvWaitAll(int sockfd, char *buf, int len); diff --git a/src/Network/Core.cpp b/src/Network/Core.cpp index bcb80509..9dec1674 100644 --- a/src/Network/Core.cpp +++ b/src/Network/Core.cpp @@ -143,7 +143,7 @@ void GetServerInfo(std::string Data) { const std::string buffer = ([&]() -> std::string { int32_t Header; std::vector data(sizeof(Header)); - int Temp = recv(ISock, data.data(), sizeof(Header), MSG_WAITALL); + int Temp = RecvWaitAll(ISock, data.data(), sizeof(Header)); auto checkBytes = ([&](const int32_t bytes) -> bool { if (bytes == 0) { @@ -164,7 +164,7 @@ void GetServerInfo(std::string Data) { } data.resize(Header, 0); - Temp = recv(ISock, data.data(), Header, MSG_WAITALL); + Temp = RecvWaitAll(ISock, data.data(), Header); if (!checkBytes(Temp)) { return ""; } diff --git a/src/Network/Resources.cpp b/src/Network/Resources.cpp index 1696dde8..26bc62e3 100644 --- a/src/Network/Resources.cpp +++ b/src/Network/Resources.cpp @@ -164,7 +164,7 @@ std::vector TCPRcvRaw(SOCKET Sock, uint64_t& GRcv, uint64_t Size) { do { // receive at most some MB at a time int Len = std::min(int(Size - Rcv), 1 * 1024 * 1024); - int Temp = recv(Sock, &File[Rcv], Len, MSG_WAITALL); + int Temp = RecvWaitAll(Sock, &File[Rcv], Len); if (Temp == -1 || Temp == 0) { debug("Recv returned: " + std::to_string(Temp)); if (Temp == -1) { From 23760da53b66d10c96c4f0c66701be1fdcf99845 Mon Sep 17 00:00:00 2001 From: Katharine Chui Date: Thu, 30 Apr 2026 20:17:05 +0200 Subject: [PATCH 3/4] do not discard received data during RecvWaitAll when the other side closes the socket cleanly --- src/Network/VehicleEvent.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Network/VehicleEvent.cpp b/src/Network/VehicleEvent.cpp index f6038de4..60a4bf56 100644 --- a/src/Network/VehicleEvent.cpp +++ b/src/Network/VehicleEvent.cpp @@ -82,7 +82,8 @@ int RecvWaitAll(int sockfd, char *buf, int len) { while (offset < len) { int recv_status = recv(sockfd, &buf[offset], len - offset, MSG_WAITALL); if (recv_status == 0) { - return 0; + // do not discard received data when the other side closes the socket cleanly + return offset; } if (recv_status == -1) { return -1; From 30639abb887241d391c6ba865f5495e3eeb23960 Mon Sep 17 00:00:00 2001 From: Katharine Chui Date: Mon, 11 May 2026 11:08:15 +0200 Subject: [PATCH 4/4] enforce expected recv size during event and server info tcp recv, remove unused instance of CheckBytes function --- include/Network/network.hpp | 2 +- src/Network/Core.cpp | 13 ++++++------- src/Network/GlobalHandler.cpp | 11 ----------- src/Network/VehicleEvent.cpp | 13 +++++++++---- 4 files changed, 16 insertions(+), 23 deletions(-) diff --git a/include/Network/network.hpp b/include/Network/network.hpp index 94e4fb52..092853e8 100644 --- a/include/Network/network.hpp +++ b/include/Network/network.hpp @@ -42,7 +42,7 @@ extern std::string magic; int KillSocket(uint64_t Dead); void UUl(const std::string& R); void UDPSend(std::string Data); -bool CheckBytes(int32_t Bytes); +bool CheckBytes(int32_t Bytes, int32_t Expected = -1); void GameSend(std::string_view Data); void SendLarge(std::string Data); std::string TCPRcv(uint64_t Sock); diff --git a/src/Network/Core.cpp b/src/Network/Core.cpp index 9dec1674..8dddfdd8 100644 --- a/src/Network/Core.cpp +++ b/src/Network/Core.cpp @@ -145,27 +145,26 @@ void GetServerInfo(std::string Data) { std::vector data(sizeof(Header)); int Temp = RecvWaitAll(ISock, data.data(), sizeof(Header)); - auto checkBytes = ([&](const int32_t bytes) -> bool { + auto checkBytes = ([&](const int32_t bytes, const int32_t expected = -1) -> bool { if (bytes == 0) { return false; } else if (bytes < 0) { return false; } + if (expected != -1 && bytes != expected) { + return false; + } return true; }); - if (!checkBytes(Temp)) { + if (!checkBytes(Temp, sizeof(Header))) { return ""; } memcpy(&Header, data.data(), sizeof(Header)); - if (!checkBytes(Temp)) { - return ""; - } - data.resize(Header, 0); Temp = RecvWaitAll(ISock, data.data(), Header); - if (!checkBytes(Temp)) { + if (!checkBytes(Temp, Header)) { return ""; } return std::string(data.data(), Header); diff --git a/src/Network/GlobalHandler.cpp b/src/Network/GlobalHandler.cpp index da4b6f28..c2290df6 100644 --- a/src/Network/GlobalHandler.cpp +++ b/src/Network/GlobalHandler.cpp @@ -50,17 +50,6 @@ int KillSocket(uint64_t Dead) { return a; } -bool CheckBytes(uint32_t Bytes) { - if (Bytes == 0) { - debug("(Proxy) Connection closing"); - return false; - } else if (Bytes < 0) { - debug("(Proxy) send failed with error: " + std::to_string(WSAGetLastError())); - return false; - } - return true; -} - void GameSend(std::string_view Data) { static std::mutex Lock; std::scoped_lock Guard(Lock); diff --git a/src/Network/VehicleEvent.cpp b/src/Network/VehicleEvent.cpp index 60a4bf56..cecacea3 100644 --- a/src/Network/VehicleEvent.cpp +++ b/src/Network/VehicleEvent.cpp @@ -28,9 +28,9 @@ int LastPort; std::string LastIP; SOCKET TCPSock = -1; -bool CheckBytes(int32_t Bytes) { +bool CheckBytes(int32_t Bytes, int32_t Expected) { if (Bytes == 0) { - debug("(TCP) Connection closing... CheckBytes(16)"); + debug("(TCP) Connection closing..."); Terminate = true; return false; } else if (Bytes < 0) { @@ -39,6 +39,11 @@ bool CheckBytes(int32_t Bytes) { Terminate = true; return false; } + if (Expected != -1 && Bytes != Expected) { + debug(std::format("(TCP) Short recv detected, expected {} bytes, got {} bytes", Expected, Bytes)); + Terminate = true; + return false; + } return true; } void UUl(const std::string& R) { @@ -103,7 +108,7 @@ std::string TCPRcv(SOCKET Sock) { int Temp; std::vector Data(sizeof(Header)); Temp = RecvWaitAll(Sock, Data.data(), sizeof(Header)); - if (!CheckBytes(Temp)) { + if (!CheckBytes(Temp, sizeof(Header))) { UUl("Socket Closed Code 3"); return ""; } @@ -116,7 +121,7 @@ std::string TCPRcv(SOCKET Sock) { Data.resize(Header, 0); Temp = RecvWaitAll(Sock, Data.data(), Header); - if (!CheckBytes(Temp)) { + if (!CheckBytes(Temp, Header)) { UUl("Socket Closed Code 5"); return ""; }