mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/LCE-Revelations.git
synced 2026-05-24 06:25:48 +00:00
fix: dedicated server thread safety, disconnect deadlock, and console freeze
- Protect PlayerList and ServerConnection players vectors with critical sections; all iterations use copy-on-read snapshots to prevent iterator invalidation during concurrent join/leave - Add null check on player bounding box in movement validation to prevent crash when player is removed mid-tick - Re-validate socket player pointer immediately before SendData to narrow the TOCTOU race window on disconnect - Replace inline disconnect cleanup with a queued system drained on the main tick thread, eliminating the done_cs -> m_playersCS lock inversion that caused deadlocks under load - Disable Windows QuickEdit mode at server startup to prevent console input selection from freezing the process - Move chunk priority sort behind ServerConnection::sortPlayersByChunkPriority() to keep the players vector lock-protected
This commit is contained in:
@@ -20,6 +20,7 @@ ServerConnection::ServerConnection(MinecraftServer *server)
|
||||
// 4J - added initialiser
|
||||
connectionCounter = 0;
|
||||
InitializeCriticalSection(&pending_cs);
|
||||
InitializeCriticalSection(&players_cs);
|
||||
|
||||
this->server = server;
|
||||
}
|
||||
@@ -27,6 +28,7 @@ ServerConnection::ServerConnection(MinecraftServer *server)
|
||||
ServerConnection::~ServerConnection()
|
||||
{
|
||||
DeleteCriticalSection(&pending_cs);
|
||||
DeleteCriticalSection(&players_cs);
|
||||
}
|
||||
|
||||
// 4J - added to handle incoming connections, to replace thread that original used to have
|
||||
@@ -38,7 +40,9 @@ void ServerConnection::NewIncomingSocket(Socket *socket)
|
||||
|
||||
void ServerConnection::addPlayerConnection(shared_ptr<PlayerConnection> uc)
|
||||
{
|
||||
EnterCriticalSection(&players_cs);
|
||||
players.push_back(uc);
|
||||
LeaveCriticalSection(&players_cs);
|
||||
}
|
||||
|
||||
void ServerConnection::handleConnection(shared_ptr<PendingConnection> uc)
|
||||
@@ -76,7 +80,9 @@ void ServerConnection::stop()
|
||||
}
|
||||
|
||||
// Snapshot to avoid iterator invalidation if disconnect modifies the vector.
|
||||
EnterCriticalSection(&players_cs);
|
||||
std::vector<shared_ptr<PlayerConnection> > playerSnapshot = players;
|
||||
LeaveCriticalSection(&players_cs);
|
||||
for (unsigned int i = 0; i < playerSnapshot.size(); i++)
|
||||
{
|
||||
shared_ptr<PlayerConnection> player = playerSnapshot[i];
|
||||
@@ -118,26 +124,34 @@ void ServerConnection::tick()
|
||||
}
|
||||
LeaveCriticalSection(&pending_cs);
|
||||
|
||||
for (unsigned int i = 0; i < players.size(); i++)
|
||||
{
|
||||
shared_ptr<PlayerConnection> player = players[i];
|
||||
shared_ptr<ServerPlayer> serverPlayer = player->getPlayer();
|
||||
if( serverPlayer )
|
||||
EnterCriticalSection(&players_cs);
|
||||
vector< shared_ptr<PlayerConnection> > tempPlayers = players;
|
||||
LeaveCriticalSection(&players_cs);
|
||||
|
||||
for (unsigned int i = 0; i < tempPlayers.size(); i++)
|
||||
{
|
||||
serverPlayer->updateFrameTick();
|
||||
serverPlayer->doChunkSendingTick(false);
|
||||
shared_ptr<PlayerConnection> player = tempPlayers[i];
|
||||
shared_ptr<ServerPlayer> serverPlayer = player->getPlayer();
|
||||
if( serverPlayer )
|
||||
{
|
||||
serverPlayer->updateFrameTick();
|
||||
serverPlayer->doChunkSendingTick(false);
|
||||
}
|
||||
player->tick();
|
||||
if (player->done)
|
||||
{
|
||||
EnterCriticalSection(&players_cs);
|
||||
auto it = find(players.begin(), players.end(), player);
|
||||
if (it != players.end()) players.erase(it);
|
||||
LeaveCriticalSection(&players_cs);
|
||||
}
|
||||
else
|
||||
{
|
||||
player->connection->flush();
|
||||
}
|
||||
}
|
||||
player->tick();
|
||||
if (player->done)
|
||||
{
|
||||
players.erase(players.begin()+i);
|
||||
i--;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->connection->flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -163,7 +177,10 @@ void ServerConnection::handleTextureReceived(const wstring &textureName)
|
||||
{
|
||||
m_pendingTextureRequests.erase(it);
|
||||
}
|
||||
for (auto& player : players)
|
||||
EnterCriticalSection(&players_cs);
|
||||
vector< shared_ptr<PlayerConnection> > tempPlayers = players;
|
||||
LeaveCriticalSection(&players_cs);
|
||||
for (auto& player : tempPlayers)
|
||||
{
|
||||
if (!player->done)
|
||||
{
|
||||
@@ -179,7 +196,10 @@ void ServerConnection::handleTextureAndGeometryReceived(const wstring &textureNa
|
||||
{
|
||||
m_pendingTextureRequests.erase(it);
|
||||
}
|
||||
for (auto& player : players)
|
||||
EnterCriticalSection(&players_cs);
|
||||
vector< shared_ptr<PlayerConnection> > tempPlayers = players;
|
||||
LeaveCriticalSection(&players_cs);
|
||||
for (auto& player : tempPlayers)
|
||||
{
|
||||
if (!player->done)
|
||||
{
|
||||
@@ -231,4 +251,46 @@ void ServerConnection::handleServerSettingsChanged(shared_ptr<ServerSettingsChan
|
||||
vector< shared_ptr<PlayerConnection> > * ServerConnection::getPlayers()
|
||||
{
|
||||
return &players;
|
||||
}
|
||||
|
||||
vector< shared_ptr<PlayerConnection> > ServerConnection::getPlayersSnapshot()
|
||||
{
|
||||
EnterCriticalSection(&players_cs);
|
||||
vector< shared_ptr<PlayerConnection> > snapshot = players;
|
||||
LeaveCriticalSection(&players_cs);
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
void ServerConnection::sortPlayersByChunkPriority()
|
||||
{
|
||||
EnterCriticalSection(&players_cs);
|
||||
if( players.size() )
|
||||
{
|
||||
vector< shared_ptr<PlayerConnection> > playersOrig = players;
|
||||
players.clear();
|
||||
|
||||
do
|
||||
{
|
||||
int longestTime = 0;
|
||||
auto playerConnectionBest = playersOrig.begin();
|
||||
for( auto it = playersOrig.begin(); it != playersOrig.end(); it++)
|
||||
{
|
||||
int thisTime = 0;
|
||||
INetworkPlayer *np = (*it)->getNetworkPlayer();
|
||||
if( np )
|
||||
{
|
||||
thisTime = np->GetTimeSinceLastChunkPacket_ms();
|
||||
}
|
||||
|
||||
if( thisTime > longestTime )
|
||||
{
|
||||
playerConnectionBest = it;
|
||||
longestTime = thisTime;
|
||||
}
|
||||
}
|
||||
players.push_back(*playerConnectionBest);
|
||||
playersOrig.erase(playerConnectionBest);
|
||||
} while ( playersOrig.size() > 0 );
|
||||
}
|
||||
LeaveCriticalSection(&players_cs);
|
||||
}
|
||||
Reference in New Issue
Block a user