From fee5a4a157f27021b7df33464717854f77f6e630 Mon Sep 17 00:00:00 2001 From: Thilo Schulz Date: Sun, 11 Oct 2009 18:31:00 +0000 Subject: [PATCH] Fix recursive error for disconnect after reliable client command overflow. Thanks to /dev/humancontroller for reporting. https://bugzilla.icculus.org/show_bug.cgi?id=3616 --- code/client/cl_cgame.c | 2 +- code/client/cl_curl.c | 2 +- code/client/cl_keys.c | 2 +- code/client/cl_main.c | 49 +++++++++++++++++++++++++----------------- code/client/cl_parse.c | 6 +++--- code/client/client.h | 2 +- 6 files changed, 36 insertions(+), 27 deletions(-) diff --git a/code/client/cl_cgame.c b/code/client/cl_cgame.c index 42fcdb74..3c351a13 100644 --- a/code/client/cl_cgame.c +++ b/code/client/cl_cgame.c @@ -467,7 +467,7 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) { Cmd_RemoveCommand( VMA(1) ); return 0; case CG_SENDCLIENTCOMMAND: - CL_AddReliableCommand( VMA(1) ); + CL_AddReliableCommand(VMA(1), qfalse); return 0; case CG_UPDATESCREEN: // this is used during lengthy level loading, so pump message loop diff --git a/code/client/cl_curl.c b/code/client/cl_curl.c index bb6d7684..a7f0879d 100644 --- a/code/client/cl_curl.c +++ b/code/client/cl_curl.c @@ -292,7 +292,7 @@ void CL_cURL_BeginDownload( const char *localName, const char *remoteURL ) if(!(clc.sv_allowDownload & DLF_NO_DISCONNECT) && !clc.cURLDisconnected) { - CL_AddReliableCommand("disconnect"); + CL_AddReliableCommand("disconnect", qtrue); CL_WritePacket(); CL_WritePacket(); CL_WritePacket(); diff --git a/code/client/cl_keys.c b/code/client/cl_keys.c index b6eb2087..0f727955 100644 --- a/code/client/cl_keys.c +++ b/code/client/cl_keys.c @@ -740,7 +740,7 @@ void Message_Key( int key ) { - CL_AddReliableCommand( buffer ); + CL_AddReliableCommand(buffer, qfalse); } Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_MESSAGE ); Field_Clear( &chatField ); diff --git a/code/client/cl_main.c b/code/client/cl_main.c index 860b7a66..67c80179 100644 --- a/code/client/cl_main.c +++ b/code/client/cl_main.c @@ -189,7 +189,7 @@ void CL_UpdateVoipIgnore(const char *idstr, qboolean ignore) if ((id >= 0) && (id < MAX_CLIENTS)) { clc.voipIgnore[id] = ignore; CL_AddReliableCommand(va("voip %s %d", - ignore ? "ignore" : "unignore", id)); + ignore ? "ignore" : "unignore", id), qfalse); Com_Printf("VoIP: %s ignoring player #%d\n", ignore ? "Now" : "No longer", id); return; @@ -251,11 +251,11 @@ void CL_Voip_f( void ) } } else if (strcmp(cmd, "muteall") == 0) { Com_Printf("VoIP: muting incoming voice\n"); - CL_AddReliableCommand("voip muteall"); + CL_AddReliableCommand("voip muteall", qfalse); clc.voipMuteAll = qtrue; } else if (strcmp(cmd, "unmuteall") == 0) { Com_Printf("VoIP: unmuting incoming voice\n"); - CL_AddReliableCommand("voip unmuteall"); + CL_AddReliableCommand("voip unmuteall", qfalse); clc.voipMuteAll = qfalse; } else { Com_Printf("usage: voip [un]ignore \n" @@ -459,17 +459,26 @@ The given command will be transmitted to the server, and is gauranteed to not have future usercmd_t executed before it is executed ====================== */ -void CL_AddReliableCommand( const char *cmd ) { - int index; - +void CL_AddReliableCommand(const char *cmd, qboolean isDisconnectCmd) +{ + int unacknowledged = clc.reliableSequence - clc.reliableAcknowledge; + // if we would be losing an old command that hasn't been acknowledged, // we must drop the connection - if ( clc.reliableSequence - clc.reliableAcknowledge > MAX_RELIABLE_COMMANDS ) { - Com_Error( ERR_DROP, "Client command overflow" ); + // also leave one slot open for the disconnect command in this case. + + if (!com_errorEntered && + ( + (isDisconnectCmd && unacknowledged > MAX_RELIABLE_COMMANDS) || + (!isDisconnectCmd && unacknowledged >= MAX_RELIABLE_COMMANDS) + ) + ) + { + Com_Error(ERR_DROP, "Client command overflow"); } - clc.reliableSequence++; - index = clc.reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 ); - Q_strncpyz( clc.reliableCommands[ index ], cmd, sizeof( clc.reliableCommands[ index ] ) ); + + Q_strncpyz(clc.reliableCommands[++clc.reliableSequence & (MAX_RELIABLE_COMMANDS - 1)], + cmd, sizeof(*clc.reliableCommands)); } /* @@ -1235,7 +1244,7 @@ void CL_Disconnect( qboolean showMainMenu ) { // send a disconnect message to the server // send it a few times in case one is dropped if ( cls.state >= CA_CONNECTED ) { - CL_AddReliableCommand( "disconnect" ); + CL_AddReliableCommand("disconnect", qtrue); CL_WritePacket(); CL_WritePacket(); CL_WritePacket(); @@ -1294,9 +1303,9 @@ void CL_ForwardCommandToServer( const char *string ) { } if ( Cmd_Argc() > 1 ) { - CL_AddReliableCommand( string ); + CL_AddReliableCommand(string, qfalse); } else { - CL_AddReliableCommand( cmd ); + CL_AddReliableCommand(cmd, qfalse); } } @@ -1438,7 +1447,7 @@ void CL_ForwardToServer_f( void ) { // don't forward the first argument if ( Cmd_Argc() > 1 ) { - CL_AddReliableCommand( Cmd_Args() ); + CL_AddReliableCommand(Cmd_Args(), qfalse); } } @@ -1678,7 +1687,7 @@ void CL_SendPureChecksums( void ) { // if we are pure we need to send back a command with our referenced pk3 checksums Com_sprintf(cMsg, sizeof(cMsg), "cp %d %s", cl.serverId, FS_ReferencedPakPureChecksums()); - CL_AddReliableCommand( cMsg ); + CL_AddReliableCommand(cMsg, qfalse); } /* @@ -1687,7 +1696,7 @@ CL_ResetPureClientAtServer ================= */ void CL_ResetPureClientAtServer( void ) { - CL_AddReliableCommand( va("vdr") ); + CL_AddReliableCommand(va("vdr"), qfalse); } /* @@ -1866,7 +1875,7 @@ void CL_DownloadsComplete( void ) { FS_Restart(clc.checksumFeed); // We possibly downloaded a pak, restart the file system to load it // inform the server so we get new gamestate info - CL_AddReliableCommand( "donedl" ); + CL_AddReliableCommand("donedl", qfalse); // by sending the donedl command we request a new gamestate // so we don't want to load stuff yet @@ -1933,7 +1942,7 @@ void CL_BeginDownload( const char *localName, const char *remoteName ) { clc.downloadBlock = 0; // Starting new file clc.downloadCount = 0; - CL_AddReliableCommand( va("download %s", remoteName) ); + CL_AddReliableCommand(va("download %s", remoteName), qfalse); } /* @@ -2592,7 +2601,7 @@ void CL_CheckUserinfo( void ) { if(cvar_modifiedFlags & CVAR_USERINFO) { cvar_modifiedFlags &= ~CVAR_USERINFO; - CL_AddReliableCommand( va("userinfo \"%s\"", Cvar_InfoString( CVAR_USERINFO ) ) ); + CL_AddReliableCommand(va("userinfo \"%s\"", Cvar_InfoString( CVAR_USERINFO ) ), qfalse); } } diff --git a/code/client/cl_parse.c b/code/client/cl_parse.c index 3c4b4fbd..588fe39b 100644 --- a/code/client/cl_parse.c +++ b/code/client/cl_parse.c @@ -552,7 +552,7 @@ void CL_ParseDownload ( msg_t *msg ) { if (!*clc.downloadTempName) { Com_Printf("Server sending download, but no download was requested\n"); - CL_AddReliableCommand( "stopdl" ); + CL_AddReliableCommand("stopdl", qfalse); return; } @@ -594,7 +594,7 @@ void CL_ParseDownload ( msg_t *msg ) { if (!clc.download) { Com_Printf( "Could not create %s\n", clc.downloadTempName ); - CL_AddReliableCommand( "stopdl" ); + CL_AddReliableCommand("stopdl", qfalse); CL_NextDownload(); return; } @@ -603,7 +603,7 @@ void CL_ParseDownload ( msg_t *msg ) { if (size) FS_Write( data, size, clc.download ); - CL_AddReliableCommand( va("nextdl %d", clc.downloadBlock) ); + CL_AddReliableCommand(va("nextdl %d", clc.downloadBlock), qfalse); clc.downloadBlock++; clc.downloadCount += size; diff --git a/code/client/client.h b/code/client/client.h index 5ee30c29..d3707782 100644 --- a/code/client/client.h +++ b/code/client/client.h @@ -431,7 +431,7 @@ extern cvar_t *cl_voip; void CL_Init (void); void CL_FlushMemory(void); void CL_ShutdownAll(void); -void CL_AddReliableCommand( const char *cmd ); +void CL_AddReliableCommand(const char *cmd, qboolean isDisconnectCmd); void CL_StartHunkUsers( qboolean rendererOnly );