mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/LCE-Revelations.git
synced 2026-06-10 05:12:57 +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:
@@ -506,7 +506,6 @@ void Socket::SocketOutputStreamNetwork::writeWithFlags(byteArray b, unsigned int
|
||||
INetworkPlayer *socketPlayer = m_socket->getPlayer();
|
||||
if(socketPlayer == nullptr)
|
||||
{
|
||||
app.DebugPrintf("Trying to write to network, but the socketPlayer is nullptr\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -518,30 +517,20 @@ void Socket::SocketOutputStreamNetwork::writeWithFlags(byteArray b, unsigned int
|
||||
bool requireAck = ( ( flags & NON_QNET_SENDDATA_ACK_REQUIRED ) == NON_QNET_SENDDATA_ACK_REQUIRED );
|
||||
#endif
|
||||
|
||||
// Re-validate the socket player immediately before use to minimize
|
||||
// the TOCTOU window where the network layer could remove the player
|
||||
// between our initial null-check and the SendData call.
|
||||
if( m_queueIdx == SOCKET_SERVER_END )
|
||||
{
|
||||
//printf( "Sent %u bytes of data from \"%ls\" to \"%ls\"\n",
|
||||
//buffer.dwDataSize,
|
||||
//hostPlayer->GetGamertag(),
|
||||
//m_socket->networkPlayer->GetGamertag());
|
||||
|
||||
hostPlayer->SendData(socketPlayer, buffer.pbyData, buffer.dwDataSize, lowPriority, requireAck);
|
||||
|
||||
// DWORD queueSize = hostPlayer->GetSendQueueSize( nullptr, QNET_GETSENDQUEUESIZE_BYTES );
|
||||
// if( queueSize > 24000 )
|
||||
// {
|
||||
// //printf("Queue size is: %d, forcing doWork()\n",queueSize);
|
||||
// g_NetworkManager.DoWork();
|
||||
// }
|
||||
INetworkPlayer *validatedPlayer = m_socket->getPlayer();
|
||||
if(validatedPlayer == nullptr) return;
|
||||
hostPlayer->SendData(validatedPlayer, buffer.pbyData, buffer.dwDataSize, lowPriority, requireAck);
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf( "Sent %u bytes of data from \"%ls\" to \"%ls\"\n",
|
||||
//buffer.dwDataSize,
|
||||
//m_socket->networkPlayer->GetGamertag(),
|
||||
//hostPlayer->GetGamertag());
|
||||
|
||||
socketPlayer->SendData(hostPlayer, buffer.pbyData, buffer.dwDataSize, lowPriority, requireAck);
|
||||
INetworkPlayer *validatedPlayer = m_socket->getPlayer();
|
||||
if(validatedPlayer == nullptr) return;
|
||||
validatedPlayer->SendData(hostPlayer, buffer.pbyData, buffer.dwDataSize, lowPriority, requireAck);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user