fix race on disconnect

between the time we check for `is_open` and the actual disconnect, the
socket could already have been disconnected by another thread (TOCTOU).
Furthermore, the disconnects can race causing a segfault or similar
issue in the asio's internals.
This commit is contained in:
Lion Kortlepel
2026-04-10 18:09:57 +02:00
parent e9ce71d39a
commit 7089e5da9a
5 changed files with 29 additions and 9 deletions
+14 -2
View File
@@ -18,6 +18,7 @@
#pragma once
#include <atomic>
#include <chrono>
#include <memory>
#include <optional>
@@ -68,8 +69,11 @@ public:
std::string GetCarPositionRaw(int Ident);
void SetUDPAddr(const ip::udp::endpoint& Addr) { mUDPAddress = Addr; }
void SetTCPSock(ip::tcp::socket&& CSock) { mSocket = std::move(CSock); }
void Disconnect(std::string_view Reason);
bool IsDisconnected() const { return !mSocket.is_open(); }
// Returns true only for the thread that actually performs socket shutdown/close.
[[nodiscard]] bool Disconnect(std::string_view Reason);
bool IsDisconnected() const {
return mDisconnectState.load(std::memory_order_acquire) != EDisconnectState::Connected;
}
// locks
void DeleteCar(int Ident);
[[nodiscard]] const std::unordered_map<std::string, std::string>& GetIdentifiers() const { return mIdentifiers; }
@@ -106,6 +110,12 @@ public:
[[nodiscard]] const std::vector<uint8_t>& GetMagic() const { return mMagic; }
private:
enum class EDisconnectState {
Connected,
Disconnecting,
Disconnected
};
void InsertVehicle(int ID, const std::string& Data);
TServer& mServer;
@@ -121,6 +131,8 @@ private:
TSetOfVehicleData mVehicleData;
SparseArray<std::string> mVehiclePosition;
std::string mName = "Unknown Client";
// Once disconnect starts, this client is terminal and its socket must be treated as dead.
std::atomic<EDisconnectState> mDisconnectState { EDisconnectState::Connected };
ip::tcp::socket mSocket;
ip::udp::endpoint mUDPAddress {};
int mUnicycleID = -1;