diff options
author | Andrey Nazarov <skuller@skuller.net> | 2011-12-15 17:49:02 +0400 |
---|---|---|
committer | Andrey Nazarov <skuller@skuller.net> | 2011-12-15 17:49:02 +0400 |
commit | 108d8ec7e63ff7a476b39bbf209580cdc5edd86b (patch) | |
tree | 9468a6ad60c12bdb7cd41a38cb8374102cd3301d /src | |
parent | 0a617d7fa96f4a8b3b2a1963f04edb594cabe530 (diff) |
Clean up SV_ExecuteClientMessage.
Diffstat (limited to 'src')
-rw-r--r-- | src/sv_main.c | 22 | ||||
-rw-r--r-- | src/sv_user.c | 313 |
2 files changed, 176 insertions, 159 deletions
diff --git a/src/sv_main.c b/src/sv_main.c index 6aa15fd..ab0a43d 100644 --- a/src/sv_main.c +++ b/src/sv_main.c @@ -1278,19 +1278,21 @@ static void SV_PacketEvent( void ) { netchan->remote_address.port = net_from.port; } - if( netchan->Process( netchan ) ) { - // this is a valid, sequenced packet, so process it - if( client->state != cs_zombie ) { - //if( client->state != cs_assigned ) { - client->lastmessage = svs.realtime; // don't timeout - //} + if( !netchan->Process( netchan ) ) + break; + + if( client->state == cs_zombie ) + break; + + // this is a valid, sequenced packet, so process it + client->lastmessage = svs.realtime; // don't timeout #if USE_ICMP - client->unreachable = qfalse; // don't drop + client->unreachable = qfalse; // don't drop #endif - SV_ExecuteClientMessage( client ); - } - } + if( netchan->dropped > 0 ) + client->frameflags |= FF_CLIENTDROP; + SV_ExecuteClientMessage( client ); break; } } diff --git a/src/sv_user.c b/src/sv_user.c index 4e25b9e..941bc62 100644 --- a/src/sv_user.c +++ b/src/sv_user.c @@ -996,6 +996,10 @@ USER CMD EXECUTION =========================================================================== */ +static qboolean moveIssued; +static int stringCmdCount; +static int userinfoUpdateCount; + /* ================== SV_ClientThink @@ -1046,9 +1050,17 @@ static void SV_SetLastFrame( int lastframe ) { SV_OldClientExecuteMove ================== */ -static void SV_OldClientExecuteMove( int net_drop ) { +static void SV_OldClientExecuteMove( void ) { usercmd_t oldest, oldcmd, newcmd; int lastframe; + int net_drop; + + if( moveIssued ) { + SV_DropClient( sv_client, "multiple clc_move commands in packet" ); + return; // someone is trying to cheat... + } + + moveIssued = qtrue; if( sv_client->protocol == PROTOCOL_VERSION_DEFAULT ) { MSG_ReadByte(); // skip over checksum @@ -1056,6 +1068,7 @@ static void SV_OldClientExecuteMove( int net_drop ) { lastframe = MSG_ReadLong(); + // read all cmds if( sv_client->protocol == PROTOCOL_VERSION_R1Q2 && sv_client->version >= PROTOCOL_VERSION_R1Q2_UCMD ) { @@ -1075,22 +1088,26 @@ static void SV_OldClientExecuteMove( int net_drop ) { SV_SetLastFrame( lastframe ); + net_drop = sv_client->netchan->dropped; if( net_drop > 2 ) { sv_client->frameflags |= FF_CLIENTPRED; } if( net_drop < 20 ) { + // run lastcmd multiple times if no backups available while( net_drop > 2 ) { SV_ClientThink( &sv_client->lastcmd ); net_drop--; } + + // run backup cmds if( net_drop > 1 ) SV_ClientThink( &oldest ); - if( net_drop > 0 ) SV_ClientThink( &oldcmd ); - } + + // run new cmd SV_ClientThink( &newcmd ); sv_client->lastcmd = newcmd; @@ -1101,12 +1118,20 @@ static void SV_OldClientExecuteMove( int net_drop ) { SV_NewClientExecuteMove ================== */ -static void SV_NewClientExecuteMove( int c, int net_drop ) { +static void SV_NewClientExecuteMove( int c ) { usercmd_t cmds[MAX_PACKET_FRAMES][MAX_PACKET_USERCMDS]; usercmd_t *lastcmd, *cmd; int lastframe; int numCmds[MAX_PACKET_FRAMES], numDups; int i, j, lightlevel; + int net_drop; + + if( moveIssued ) { + SV_DropClient( sv_client, "multiple clc_move commands in packet" ); + return; // someone is trying to cheat... + } + + moveIssued = qtrue; numDups = c >> SVCMD_BITS; c &= SVCMD_MASK; @@ -1159,6 +1184,7 @@ static void SV_NewClientExecuteMove( int c, int net_drop ) { return; // should never happen } + net_drop = sv_client->netchan->dropped; if( net_drop > numDups ) { sv_client->frameflags |= FF_CLIENTPRED; } @@ -1233,6 +1259,81 @@ static void SV_UpdateUserinfo( void ) { SV_UserinfoChanged( sv_client ); } +static void SV_ParseFullUserinfo( void ) { + size_t len; + + // malicious users may try sending too many userinfo updates + if( userinfoUpdateCount >= MAX_PACKET_USERINFOS ) { + Com_DPrintf( "Too many userinfos from %s\n", sv_client->name ); + MSG_ReadString( NULL, 0 ); + return; + } + + len = MSG_ReadString( sv_client->userinfo, sizeof( sv_client->userinfo ) ); + if( len >= sizeof( sv_client->userinfo ) ) { + SV_DropClient( sv_client, "oversize userinfo" ); + return; + } + + Com_DDPrintf( "%s(%s): %s [%d]\n", __func__, + sv_client->name, sv_client->userinfo, userinfoUpdateCount ); + + SV_UpdateUserinfo(); + userinfoUpdateCount++; +} + +static void SV_ParseDeltaUserinfo( void ) { + char key[MAX_INFO_KEY], value[MAX_INFO_VALUE]; + size_t len; + + // malicious users may try sending too many userinfo updates + if( userinfoUpdateCount >= MAX_PACKET_USERINFOS ) { + Com_DPrintf( "Too many userinfos from %s\n", sv_client->name ); + MSG_ReadString( NULL, 0 ); + MSG_ReadString( NULL, 0 ); + return; + } + + // optimize by combining multiple delta updates into one (hack) + while( 1 ) { + len = MSG_ReadString( key, sizeof( key ) ); + if( len >= sizeof( key ) ) { + SV_DropClient( sv_client, "oversize delta key" ); + return; + } + + len = MSG_ReadString( value, sizeof( value ) ); + if( len >= sizeof( value ) ) { + SV_DropClient( sv_client, "oversize delta value" ); + return; + } + + if( userinfoUpdateCount < MAX_PACKET_USERINFOS ) { + if( !Info_SetValueForKey( sv_client->userinfo, key, value ) ) { + SV_DropClient( sv_client, "malformed userinfo" ); + return; + } + + Com_DDPrintf( "%s(%s): %s %s [%d]\n", __func__, + sv_client->name, key, value, userinfoUpdateCount ); + + userinfoUpdateCount++; + } else { + Com_DPrintf( "Too many userinfos from %s\n", sv_client->name ); + } + + if( msg_read.readcount >= msg_read.cursize ) + break; // end of message + + if( msg_read.data[msg_read.readcount] != clc_userinfo_delta ) + break; // not delta userinfo + + msg_read.readcount++; + } + + SV_UpdateUserinfo(); +} + #if USE_FPS static void align_key_frames( void ) { int framediv = sv.framediv / sv_client->framediv; @@ -1277,6 +1378,47 @@ static void set_client_fps( int value ) { } #endif +static void SV_ParseClientSetting( void ) { + int idx, value; + + idx = MSG_ReadShort(); + value = MSG_ReadShort(); + + Com_DDPrintf( "%s(%s): [%d] = %d\n", __func__, sv_client->name, idx, value ); + + if( idx < 0 || idx >= CLS_MAX ) + return; + + sv_client->settings[idx] = value; + +#if USE_FPS + if( idx == CLS_FPS && sv_client->protocol == PROTOCOL_VERSION_Q2PRO ) + set_client_fps( value ); +#endif +} + +static void SV_ParseClientCommand( void ) { + char buffer[MAX_STRING_CHARS]; + size_t len; + + len = MSG_ReadString( buffer, sizeof( buffer ) ); + if( len >= sizeof( buffer ) ) { + SV_DropClient( sv_client, "oversize stringcmd" ); + return; + } + + // malicious users may try using too many string commands + if( stringCmdCount >= MAX_PACKET_STRINGCMDS ) { + Com_DPrintf( "Too many stringcmds from %s\n", sv_client->name ); + return; + } + + Com_DDPrintf( "%s(%s): %s\n", __func__, sv_client->name, buffer ); + + SV_ExecuteUserCommand( buffer ); + stringCmdCount++; +} + /* =================== SV_ExecuteClientMessage @@ -1285,12 +1427,7 @@ The current net_message is parsed for the given client =================== */ void SV_ExecuteClientMessage( client_t *client ) { - int c; - qboolean move_issued; - int stringCmdCount; - int userinfoUpdateCount; - int net_drop; - size_t len; + int c; X86_PUSH_FPCW; X86_SINGLE_FPCW; @@ -1299,15 +1436,10 @@ void SV_ExecuteClientMessage( client_t *client ) { sv_player = sv_client->edict; // only allow one move command - move_issued = qfalse; + moveIssued = qfalse; stringCmdCount = 0; userinfoUpdateCount = 0; - net_drop = client->netchan->dropped; - if( net_drop > 0 ) { - client->frameflags |= FF_CLIENTDROP; - } - while( 1 ) { if( msg_read.readcount > msg_read.cursize ) { SV_DropClient( client, "read past end of message" ); @@ -1327,162 +1459,45 @@ void SV_ExecuteClientMessage( client_t *client ) { case clc_nop: break; - case clc_userinfo: { - // malicious users may try sending too many userinfo updates - if( userinfoUpdateCount == MAX_PACKET_USERINFOS ) { - Com_DPrintf( "Too many userinfos from %s\n", client->name ); - MSG_ReadString( NULL, 0 ); - break; - } - - len = MSG_ReadString( sv_client->userinfo, sizeof( sv_client->userinfo ) ); - if( len >= sizeof( sv_client->userinfo ) ) { - SV_DropClient( client, "oversize userinfo" ); - break; - } - - SV_UpdateUserinfo(); - userinfoUpdateCount++; - } + case clc_userinfo: + SV_ParseFullUserinfo(); break; case clc_move: - if( move_issued ) { - SV_DropClient( client, "multiple clc_move commands in packet" ); - break; // someone is trying to cheat... - } - - move_issued = qtrue; - - SV_OldClientExecuteMove( net_drop ); + SV_OldClientExecuteMove(); break; - case clc_stringcmd: { - char buffer[MAX_STRING_CHARS]; - - len = MSG_ReadString( buffer, sizeof( buffer ) ); - if( len >= sizeof( buffer ) ) { - SV_DropClient( client, "oversize stringcmd" ); - break; - } - - Com_DDPrintf( "ClientCommand( %s ): %s\n", - client->name, buffer ); - - if( !NET_IsLocalAddress( &client->netchan->remote_address ) ) { - // malicious users may try using too many string commands - if( stringCmdCount == MAX_PACKET_STRINGCMDS ) { - Com_DPrintf( "Too many stringcmds from %s\n", client->name ); - break; - } - } - SV_ExecuteUserCommand( buffer ); - stringCmdCount++; - } + case clc_stringcmd: + SV_ParseClientCommand(); break; - // r1q2 specific operations - case clc_setting: { - uint16_t idx, value; - - if( client->protocol < PROTOCOL_VERSION_R1Q2 ) { - goto badbyte; - } + case clc_setting: + if( client->protocol < PROTOCOL_VERSION_R1Q2 ) + goto badbyte; - idx = MSG_ReadShort(); - value = MSG_ReadShort(); - if( idx < CLS_MAX ) { - client->settings[idx] = value; -#if USE_FPS - if( idx == CLS_FPS && client->protocol == PROTOCOL_VERSION_Q2PRO ) - set_client_fps( value ); -#endif - } - } + SV_ParseClientSetting(); break; - - // q2pro specific operations case clc_move_nodelta: case clc_move_batched: - if( client->protocol != PROTOCOL_VERSION_Q2PRO ) { + if( client->protocol != PROTOCOL_VERSION_Q2PRO ) goto badbyte; - } - - if( move_issued ) { - SV_DropClient( client, "multiple clc_move commands in packet" ); - break; // someone is trying to cheat... - } - move_issued = qtrue; - SV_NewClientExecuteMove( c, net_drop ); + SV_NewClientExecuteMove( c ); break; - case clc_userinfo_delta: { - char key[MAX_INFO_KEY], value[MAX_INFO_VALUE]; - - if( client->protocol != PROTOCOL_VERSION_Q2PRO ) { - goto badbyte; - } - - // malicious users may try sending too many userinfo updates - if( userinfoUpdateCount == MAX_PACKET_USERINFOS ) { - Com_DPrintf( "Too many userinfos from %s\n", client->name ); - MSG_ReadString( NULL, 0 ); - MSG_ReadString( NULL, 0 ); - break; - } - - // optimize by combining multiple delta updates into one (hack) - while( 1 ) { - len = MSG_ReadString( key, sizeof( key ) ); - if( len >= sizeof( key ) ) { - SV_DropClient( client, "oversize delta key" ); - goto finish; - } - - len = MSG_ReadString( value, sizeof( value ) ); - if( len >= sizeof( value ) ) { - SV_DropClient( client, "oversize delta value" ); - goto finish; - } - - if( userinfoUpdateCount < MAX_PACKET_USERINFOS ) { - if( !Info_SetValueForKey( sv_client->userinfo, key, value ) ) { - SV_DropClient( client, "malformed delta userinfo" ); - goto finish; - } - - Com_DDPrintf( "DeltaUserinfo( %s ): %s %s [%d]\n", - client->name, key, value, userinfoUpdateCount ); - - userinfoUpdateCount++; - } else { - Com_DPrintf( "Too many userinfos from %s\n", client->name ); - } - - if( msg_read.readcount >= msg_read.cursize ) { - break; // end of message - } - - if( msg_read.data[msg_read.readcount] != clc_userinfo_delta ) { - break; // not delta userinfo - } - - msg_read.readcount++; - } + case clc_userinfo_delta: + if( client->protocol != PROTOCOL_VERSION_Q2PRO ) + goto badbyte; - SV_UpdateUserinfo(); - } + SV_ParseDeltaUserinfo(); break; } - if( client->state < cs_assigned ) { + if( client->state <= cs_zombie ) break; // disconnect command - } } -finish: sv_client = NULL; sv_player = NULL; |