diff options
author | Andrey Nazarov <skuller@skuller.net> | 2008-06-29 12:32:32 +0000 |
---|---|---|
committer | Andrey Nazarov <skuller@skuller.net> | 2008-06-29 12:32:32 +0000 |
commit | e826e5f176f21cd18b3bbc22887a266835ada57c (patch) | |
tree | d25a84a84f9168b16a77fe4ed8b169c9611bbb02 /source/sv_user.c | |
parent | 491f1c100e860c45a5d2aa358d58f777cd1cf895 (diff) |
Added client and server side support for 32-bit solids.
New R1Q2 and Q2PRO minor protocol versions, 1905 and 1014.
Use environment variables for game and server features negotiation.
Relax restrictions on quake paths when searching inside pak files.
Made OSS subsystem cvar names consistent with core sound system conventions.
Misc latched cvar handling changes.
Diffstat (limited to 'source/sv_user.c')
-rw-r--r-- | source/sv_user.c | 1345 |
1 files changed, 676 insertions, 669 deletions
diff --git a/source/sv_user.c b/source/sv_user.c index 3e7c845..0c29983 100644 --- a/source/sv_user.c +++ b/source/sv_user.c @@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sv_local.h" #include "mvd_local.h" -edict_t *sv_player; +edict_t *sv_player; /* ============================================================ @@ -43,85 +43,94 @@ baseline will be transmitted ================ */ static void create_baselines( void ) { - int i; - edict_t *ent; - entity_state_t *base, **chunk; - - // clear baselines from previous level - for( i = 0; i < SV_BASELINES_CHUNKS; i++ ) { - base = sv_client->baselines[i]; - if( !base ) { - continue; - } - memset( base, 0, sizeof( *base ) * SV_BASELINES_PER_CHUNK ); - } - - for( i = 1; i < sv_client->pool->num_edicts; i++ ) { - ent = EDICT_POOL( sv_client, i ); - - if( ( g_features->integer & GMF_PROPERINUSE ) && !ent->inuse ) { + int i; + edict_t *ent; + entity_state_t *base, **chunk; + + // clear baselines from previous level + for( i = 0; i < SV_BASELINES_CHUNKS; i++ ) { + base = sv_client->baselines[i]; + if( !base ) { + continue; + } + memset( base, 0, sizeof( *base ) * SV_BASELINES_PER_CHUNK ); + } + + for( i = 1; i < sv_client->pool->num_edicts; i++ ) { + ent = EDICT_POOL( sv_client, i ); + + if( ( svs.gameFeatures & GMF_PROPERINUSE ) && !ent->inuse ) { continue; } - if( !ES_INUSE( &ent->s ) ) { - continue; - } + if( !ES_INUSE( &ent->s ) ) { + continue; + } - ent->s.number = i; + ent->s.number = i; - chunk = &sv_client->baselines[i >> SV_BASELINES_SHIFT]; - if( *chunk == NULL ) { - *chunk = SV_Mallocz( sizeof( *base ) * SV_BASELINES_PER_CHUNK ); - } + chunk = &sv_client->baselines[i >> SV_BASELINES_SHIFT]; + if( *chunk == NULL ) { + *chunk = SV_Mallocz( sizeof( *base ) * SV_BASELINES_PER_CHUNK ); + } - base = *chunk + ( i & SV_BASELINES_MASK ); + base = *chunk + ( i & SV_BASELINES_MASK ); - *base = ent->s; - } + *base = ent->s; + } } static void write_plain_configstrings( void ) { - int i; - char *string; - size_t length; - - // write a packet full of data - string = sv_client->configstrings; - for( i = 0; i < MAX_CONFIGSTRINGS; i++, string += MAX_QPATH ) { - if( !string[0] ) { - continue; - } - length = strlen( string ); - if( length > MAX_QPATH ) { - length = MAX_QPATH; - } - // check if this configstring will overflow - if( msg_write.cursize + length + 64 > sv_client->netchan->maxpacketlen ) + int i; + char *string; + size_t length; + + // write a packet full of data + string = sv_client->configstrings; + for( i = 0; i < MAX_CONFIGSTRINGS; i++, string += MAX_QPATH ) { + if( !string[0] ) { + continue; + } + length = strlen( string ); + if( length > MAX_QPATH ) { + length = MAX_QPATH; + } + // check if this configstring will overflow + if( msg_write.cursize + length + 64 > sv_client->netchan->maxpacketlen ) { - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); } - MSG_WriteByte( svc_configstring ); - MSG_WriteShort( i ); - MSG_WriteData( string, length ); - MSG_WriteByte( 0 ); - } + MSG_WriteByte( svc_configstring ); + MSG_WriteShort( i ); + MSG_WriteData( string, length ); + MSG_WriteByte( 0 ); + } - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); +} + +static void write_baseline( entity_state_t *base ) { + msgEsFlags_t flags = MSG_ES_FORCE; + + if( LONG_SOLID_SUPPORTED( sv_client->protocol, sv_client->version ) ) { + flags |= MSG_ES_LONGSOLID; + } + MSG_WriteDeltaEntity( NULL, base, flags ); } static void write_plain_baselines( void ) { - int i, j; - entity_state_t *base; + int i, j; + entity_state_t *base; - // write a packet full of data + // write a packet full of data for( i = 0; i < SV_BASELINES_CHUNKS; i++ ) { - base = sv_client->baselines[i]; - if( !base ) { - continue; - } - for( j = 0; j < SV_BASELINES_PER_CHUNK; j++ ) { + base = sv_client->baselines[i]; + if( !base ) { + continue; + } + for( j = 0; j < SV_BASELINES_PER_CHUNK; j++ ) { if( base->number ) { // check if this baseline will overflow if( msg_write.cursize + 64 > sv_client->netchan->maxpacketlen ) @@ -130,71 +139,71 @@ static void write_plain_baselines( void ) { } MSG_WriteByte( svc_spawnbaseline ); - MSG_WriteDeltaEntity( NULL, base, MSG_ES_FORCE ); + write_baseline( base ); } base++; } - } + } - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); } #if USE_ZLIB static void write_compressed_gamestate( void ) { - sizebuf_t *buf = &sv_client->netchan->message; - entity_state_t *base; - int i, j; - size_t length; + sizebuf_t *buf = &sv_client->netchan->message; + entity_state_t *base; + int i, j; + size_t length; uint8_t *patch; char *string; MSG_WriteByte( svc_gamestate ); - // write configstrings + // write configstrings string = sv_client->configstrings; - for( i = 0; i < MAX_CONFIGSTRINGS; i++, string += MAX_QPATH ) { - if( !string[0] ) { - continue; - } - length = strlen( string ); - if( length > MAX_QPATH ) { - length = MAX_QPATH; - } - - MSG_WriteShort( i ); - MSG_WriteData( string, length ); - MSG_WriteByte( 0 ); - } + for( i = 0; i < MAX_CONFIGSTRINGS; i++, string += MAX_QPATH ) { + if( !string[0] ) { + continue; + } + length = strlen( string ); + if( length > MAX_QPATH ) { + length = MAX_QPATH; + } + + MSG_WriteShort( i ); + MSG_WriteData( string, length ); + MSG_WriteByte( 0 ); + } MSG_WriteShort( MAX_CONFIGSTRINGS ); // end of configstrings // write baselines for( i = 0; i < SV_BASELINES_CHUNKS; i++ ) { - base = sv_client->baselines[i]; - if( !base ) { - continue; - } - for( j = 0; j < SV_BASELINES_PER_CHUNK; j++ ) { + base = sv_client->baselines[i]; + if( !base ) { + continue; + } + for( j = 0; j < SV_BASELINES_PER_CHUNK; j++ ) { if( base->number ) { - MSG_WriteDeltaEntity( NULL, base, MSG_ES_FORCE ); + write_baseline( base ); } base++; } - } + } MSG_WriteShort( 0 ); // end of baselines - SZ_WriteByte( buf, svc_zpacket ); + SZ_WriteByte( buf, svc_zpacket ); patch = SZ_GetSpace( buf, 2 ); - SZ_WriteShort( buf, msg_write.cursize ); + SZ_WriteShort( buf, msg_write.cursize ); deflateReset( &svs.z ); svs.z.next_in = msg_write.data; svs.z.avail_in = ( uInt )msg_write.cursize; svs.z.next_out = buf->data + buf->cursize; svs.z.avail_out = ( uInt )( buf->maxsize - buf->cursize ); - SZ_Clear( &msg_write ); + SZ_Clear( &msg_write ); - if( deflate( &svs.z, Z_FINISH ) != Z_STREAM_END ) { + if( deflate( &svs.z, Z_FINISH ) != Z_STREAM_END ) { SV_DropClient( sv_client, "deflate() failed on gamestate" ); return; } @@ -213,23 +222,23 @@ static inline int z_flush( byte *buffer ) { int ret; ret = deflate( &svs.z, Z_FINISH ); - if( ret != Z_STREAM_END ) { - return ret; - } + if( ret != Z_STREAM_END ) { + return ret; + } if( sv_debug_send->integer ) { Com_Printf( S_COLOR_BLUE"%s: comp: %lu into %lu\n", sv_client->name, svs.z.total_in, svs.z.total_out ); } - MSG_WriteByte( svc_zpacket ); - MSG_WriteShort( svs.z.total_out ); - MSG_WriteShort( svs.z.total_in ); - MSG_WriteData( buffer, svs.z.total_out ); - - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + MSG_WriteByte( svc_zpacket ); + MSG_WriteShort( svs.z.total_out ); + MSG_WriteShort( svs.z.total_in ); + MSG_WriteData( buffer, svs.z.total_out ); + + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); - return ret; + return ret; } static inline void z_reset( byte *buffer ) { @@ -239,52 +248,52 @@ static inline void z_reset( byte *buffer ) { } static void write_compressed_configstrings( void ) { - int i; - size_t length; - byte buffer[MAX_PACKETLEN_WRITABLE]; - char *string; + int i; + size_t length; + byte buffer[MAX_PACKETLEN_WRITABLE]; + char *string; z_reset( buffer ); - // write a packet full of data + // write a packet full of data string = sv_client->configstrings; - for( i = 0; i < MAX_CONFIGSTRINGS; i++, string += MAX_QPATH ) { - if( !string[0] ) { - continue; - } - length = strlen( string ); - if( length > MAX_QPATH ) { - length = MAX_QPATH; - } - - // check if this configstring will overflow - if( svs.z.avail_out < length + 32 ) { - // then flush compressed data - if( z_flush( buffer ) != Z_STREAM_END ) { + for( i = 0; i < MAX_CONFIGSTRINGS; i++, string += MAX_QPATH ) { + if( !string[0] ) { + continue; + } + length = strlen( string ); + if( length > MAX_QPATH ) { + length = MAX_QPATH; + } + + // check if this configstring will overflow + if( svs.z.avail_out < length + 32 ) { + // then flush compressed data + if( z_flush( buffer ) != Z_STREAM_END ) { goto fail; - } + } z_reset( buffer ); - } + } - MSG_WriteByte( svc_configstring ); - MSG_WriteShort( i ); - MSG_WriteData( string, length ); - MSG_WriteByte( 0 ); + MSG_WriteByte( svc_configstring ); + MSG_WriteShort( i ); + MSG_WriteData( string, length ); + MSG_WriteByte( 0 ); svs.z.next_in = msg_write.data; svs.z.avail_in = ( uInt )msg_write.cursize; SZ_Clear( &msg_write ); - if( deflate( &svs.z, Z_SYNC_FLUSH ) != Z_OK ) { + if( deflate( &svs.z, Z_SYNC_FLUSH ) != Z_OK ) { goto fail; } - } + } - // finally flush all remaining compressed data - if( z_flush( buffer ) != Z_STREAM_END ) { + // finally flush all remaining compressed data + if( z_flush( buffer ) != Z_STREAM_END ) { fail: SV_DropClient( sv_client, "deflate() failed on configstrings" ); - } + } } #endif // USE_ZLIB @@ -297,7 +306,7 @@ static void stuff_cmds( list_t *list ) { MSG_WriteData( stuff->string, stuff->len ); MSG_WriteByte( '\n' ); MSG_WriteByte( 0 ); - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); } } @@ -316,18 +325,18 @@ void SV_New_f( void ) { char junk[8][16]; int i, j, c; - Com_DPrintf( "New() from %s\n", sv_client->name ); + Com_DPrintf( "New() from %s\n", sv_client->name ); if( sv_client->state < cs_connected ) { - Com_DPrintf( "Going from cs_assigned to cs_connected for %s\n", + Com_DPrintf( "Going from cs_assigned to cs_connected for %s\n", sv_client->name ); sv_client->state = cs_connected; sv_client->lastmessage = svs.realtime; // don't timeout time( &sv_client->connect_time ); } else if( sv_client->state > cs_connected ) { - Com_DPrintf( "New not valid -- already primed\n" ); - return; - } + Com_DPrintf( "New not valid -- already primed\n" ); + return; + } if( sv_force_reconnect->string[0] && !sv_client->reconnect_var[0] && !NET_IsLocalAddress( &sv_client->netchan->remote_address ) ) @@ -363,89 +372,89 @@ void SV_New_f( void ) { return; } - SV_ClientCommand( sv_client, "\n" ); + SV_ClientCommand( sv_client, "\n" ); - // - // serverdata needs to go over for all types of servers - // to make sure the protocol is right, and to set the gamedir - // + // + // serverdata needs to go over for all types of servers + // to make sure the protocol is right, and to set the gamedir + // // create baselines for this client create_baselines(); - // send the serverdata - MSG_WriteByte( svc_serverdata ); - MSG_WriteLong( sv_client->protocol ); - MSG_WriteLong( sv.spawncount ); - MSG_WriteByte( 0 ); // no attract loop - MSG_WriteString( sv_client->gamedir ); - MSG_WriteShort( sv_client->slot ); - MSG_WriteString( &sv_client->configstrings[CS_NAME*MAX_QPATH] ); - - // send protocol specific stuff - switch( sv_client->protocol ) { - case PROTOCOL_VERSION_R1Q2: - MSG_WriteByte( 0 ); // not enhanced - MSG_WriteShort( sv_client->version ); - MSG_WriteByte( 0 ); // no advanced deltas - MSG_WriteByte( sv_strafejump_hack->integer ? 1 : 0 ); - break; - case PROTOCOL_VERSION_Q2PRO: - MSG_WriteShort( sv_client->version ); - MSG_WriteByte( svs.gametype ); - MSG_WriteByte( sv_strafejump_hack->integer ? 1 : 0 ); - MSG_WriteByte( sv_qwmod->integer ); - break; - default: - break; - } - - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); - - SV_ClientCommand( sv_client, "\n" ); - - // send version string request - if( !sv_client->versionString ) { - SV_ClientCommand( sv_client, "cmd \177c version $version\n" + // send the serverdata + MSG_WriteByte( svc_serverdata ); + MSG_WriteLong( sv_client->protocol ); + MSG_WriteLong( sv.spawncount ); + MSG_WriteByte( 0 ); // no attract loop + MSG_WriteString( sv_client->gamedir ); + MSG_WriteShort( sv_client->slot ); + MSG_WriteString( &sv_client->configstrings[CS_NAME*MAX_QPATH] ); + + // send protocol specific stuff + switch( sv_client->protocol ) { + case PROTOCOL_VERSION_R1Q2: + MSG_WriteByte( 0 ); // not enhanced + MSG_WriteShort( sv_client->version ); + MSG_WriteByte( 0 ); // no advanced deltas + MSG_WriteByte( sv_strafejump_hack->integer ? 1 : 0 ); + break; + case PROTOCOL_VERSION_Q2PRO: + MSG_WriteShort( sv_client->version ); + MSG_WriteByte( 2 ); // used to be GT_DEATHMATCH + MSG_WriteByte( sv_strafejump_hack->integer ? 1 : 0 ); + MSG_WriteByte( sv_qwmod->integer ); + break; + default: + break; + } + + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + + SV_ClientCommand( sv_client, "\n" ); + + // send version string request + if( !sv_client->versionString ) { + SV_ClientCommand( sv_client, "cmd \177c version $version\n" #if USE_ANTICHEAT & 2 "cmd \177c actoken $actoken\n" #endif ); stuff_cmds( &sv_cmdlist_connect ); - } + } // send reconnect var request if( sv_force_reconnect->string[0] && !( sv_client->flags & CF_RECONNECTED ) ) { - SV_ClientCommand( sv_client, "cmd \177c connect $%s\n", + SV_ClientCommand( sv_client, "cmd \177c connect $%s\n", sv_client->reconnect_var ); } - Com_DPrintf( "Going from cs_connected to cs_primed for %s\n", + Com_DPrintf( "Going from cs_connected to cs_primed for %s\n", sv_client->name ); - sv_client->state = cs_primed; + sv_client->state = cs_primed; - memset( &sv_client->lastcmd, 0, sizeof( sv_client->lastcmd ) ); + memset( &sv_client->lastcmd, 0, sizeof( sv_client->lastcmd ) ); #if USE_ZLIB if( !( sv_client->flags & CF_DEFLATE ) ) { - write_plain_configstrings(); - write_plain_baselines(); + write_plain_configstrings(); + write_plain_baselines(); } else { if( sv_client->netchan->type == NETCHAN_NEW ) { write_compressed_gamestate(); } else { // FIXME: Z_SYNC_FLUSH is not efficient for baselines write_compressed_configstrings(); - write_plain_baselines(); + write_plain_baselines(); } - } + } #else // USE_ZLIB - write_plain_configstrings(); - write_plain_baselines(); + write_plain_configstrings(); + write_plain_baselines(); #endif // !USE_ZLIB - // send next command - SV_ClientCommand( sv_client, "precache %i\n", sv.spawncount ); + // send next command + SV_ClientCommand( sv_client, "precache %i\n", sv.spawncount ); } /* @@ -454,18 +463,18 @@ SV_Begin_f ================== */ void SV_Begin_f( void ) { - Com_DPrintf( "Begin() from %s\n", sv_client->name ); - - // handle the case of a level changing while a client was connecting - if( sv_client->state < cs_primed ) { - Com_DPrintf( "Begin not valid -- not yet primed\n" ); - SV_New_f(); - return; - } - if( sv_client->state > cs_primed ) { - Com_DPrintf( "Begin not valid -- already spawned\n" ); - return; - } + Com_DPrintf( "Begin() from %s\n", sv_client->name ); + + // handle the case of a level changing while a client was connecting + if( sv_client->state < cs_primed ) { + Com_DPrintf( "Begin not valid -- not yet primed\n" ); + SV_New_f(); + return; + } + if( sv_client->state > cs_primed ) { + Com_DPrintf( "Begin not valid -- already spawned\n" ); + return; + } if( sv_force_reconnect->string[0] && !( sv_client->flags & CF_RECONNECTED ) ) { if( dedicated->integer ) { @@ -482,17 +491,17 @@ void SV_Begin_f( void ) { } #endif - Com_DPrintf( "Going from cs_primed to cs_spawned for %s\n", + Com_DPrintf( "Going from cs_primed to cs_spawned for %s\n", sv_client->name ); - sv_client->state = cs_spawned; - sv_client->send_delta = 0; - sv_client->commandMsec = 1800; + sv_client->state = cs_spawned; + sv_client->send_delta = 0; + sv_client->commandMsec = 1800; sv_client->surpressCount = 0; stuff_cmds( &sv_cmdlist_begin ); - - // call the game begin function - ge->ClientBegin( sv_player ); + + // call the game begin function + ge->ClientBegin( sv_player ); #if USE_ANTICHEAT & 2 AC_ClientAnnounce( sv_client ); @@ -501,7 +510,7 @@ void SV_Begin_f( void ) { //============================================================================= -#define MAX_DOWNLOAD_CHUNK 1024 +#define MAX_DOWNLOAD_CHUNK 1024 /* ================== @@ -509,42 +518,42 @@ SV_NextDownload_f ================== */ static void SV_NextDownload_f( void ) { - int r; - int percent; - int size; - - if ( !sv_client->download ) - return; - - r = sv_client->downloadsize - sv_client->downloadcount; - if ( r > MAX_DOWNLOAD_CHUNK ) - r = MAX_DOWNLOAD_CHUNK; - - MSG_WriteByte( svc_download ); - MSG_WriteShort( r ); - - sv_client->downloadcount += r; - size = sv_client->downloadsize; - if( !size ) - size = 1; - percent = sv_client->downloadcount*100/size; - MSG_WriteByte( percent ); - MSG_WriteData( sv_client->download + sv_client->downloadcount - r, r ); - - if( sv_client->downloadcount == sv_client->downloadsize ) { - Z_Free( sv_client->download ); - sv_client->download = NULL; - } - - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + int r; + int percent; + int size; + + if ( !sv_client->download ) + return; + + r = sv_client->downloadsize - sv_client->downloadcount; + if ( r > MAX_DOWNLOAD_CHUNK ) + r = MAX_DOWNLOAD_CHUNK; + + MSG_WriteByte( svc_download ); + MSG_WriteShort( r ); + + sv_client->downloadcount += r; + size = sv_client->downloadsize; + if( !size ) + size = 1; + percent = sv_client->downloadcount*100/size; + MSG_WriteByte( percent ); + MSG_WriteData( sv_client->download + sv_client->downloadcount - r, r ); + + if( sv_client->downloadcount == sv_client->downloadsize ) { + Z_Free( sv_client->download ); + sv_client->download = NULL; + } + + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); } static void SV_DownloadFailed( void ) { - MSG_WriteByte( svc_download ); - MSG_WriteShort( -1 ); - MSG_WriteByte( 0 ); - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + MSG_WriteByte( svc_download ); + MSG_WriteShort( -1 ); + MSG_WriteByte( 0 ); + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); } /* @@ -553,133 +562,133 @@ SV_BeginDownload_f ================== */ static void SV_BeginDownload_f( void ) { - char name[MAX_QPATH]; - int downloadsize; - int offset = 0; - cvar_t *allow; - int length; - char *filename; - - length = Q_ClearStr( name, Cmd_Argv( 1 ), sizeof( name ) ); - Q_strlwr( name ); - - if( Cmd_Argc() > 2 ) - offset = atoi( Cmd_Argv( 2 ) ); // downloaded offset - - // hacked by zoid to allow more conrol over download - // first off, no .. or global allow check - if( !allow_download->integer - // check for empty paths - || !length - // check for illegal negative offsets - || offset < 0 - // don't allow anything with .. path - || strstr( name, ".." ) - // leading dots, slashes, etc are no good - || !Q_ispath( name[0] ) - // trailing dots, slashes, etc are no good - || !Q_ispath( name[ length - 1 ] ) - // back slashes should be never sent - || strchr( name, '\\' ) - // colons are bad also - || strchr( name, ':' ) - // MUST be in a subdirectory - || !strchr( name, '/' ) ) - { - SV_DownloadFailed(); - return; - } - - if( strncmp( name, "players/", 8 ) == 0 ) { - allow = allow_download_players; - } else if( strncmp( name, "models/", 7 ) == 0 ) { - allow = allow_download_models; - } else if( strncmp( name, "sound/", 6 ) == 0 ) { - allow = allow_download_sounds; - } else if( strncmp( name, "maps/", 5 ) == 0 ) { - allow = allow_download_maps; - } else { - allow = allow_download_other; - } - - if( !allow->integer ) { - Com_DPrintf( "Refusing download of %s to %s\n", name, sv_client->name ); - SV_DownloadFailed(); - return; - } - - if( sv_client->download ) { - Com_DPrintf( "Closing existing download for %s (should not happen)\n", sv_client->name ); - FS_FreeFile( sv_client->download ); - sv_client->download = NULL; - } - - filename = name; - - downloadsize = FS_LoadFileEx( filename, NULL, 0, TAG_SERVER ); - - if( downloadsize == INVALID_LENGTH || downloadsize == 0 - // special check for maps, if it came from a pak file, don't allow - // download ZOID - || ( allow == allow_download_maps - && allow_download_maps->integer < 2 - && FS_LastFileFromPak() ) ) - { - Com_DPrintf( "Couldn't download %s to %s\n", name, sv_client->name ); - SV_DownloadFailed(); - return; - } - - if( offset > downloadsize ) { - Com_DPrintf( "Refusing download, %s has wrong version of %s (%d > %d)\n", - sv_client->name, name, offset, downloadsize ); - SV_ClientPrintf( sv_client, PRINT_HIGH, "File size differs from server.\n" - "Please delete the corresponding .tmp file from your system.\n" ); - SV_DownloadFailed(); - return; - } - - if( offset == downloadsize ) { - Com_DPrintf( "Refusing download, %s already has %s (%d bytes)\n", - sv_client->name, name, offset ); - MSG_WriteByte( svc_download ); - MSG_WriteShort( 0 ); - MSG_WriteByte( 100 ); - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); - return; - } - - sv_client->downloadsize = FS_LoadFileEx( filename, + char name[MAX_QPATH]; + int downloadsize; + int offset = 0; + cvar_t *allow; + int length; + char *filename; + + length = Q_ClearStr( name, Cmd_Argv( 1 ), sizeof( name ) ); + Q_strlwr( name ); + + if( Cmd_Argc() > 2 ) + offset = atoi( Cmd_Argv( 2 ) ); // downloaded offset + + // hacked by zoid to allow more conrol over download + // first off, no .. or global allow check + if( !allow_download->integer + // check for empty paths + || !length + // check for illegal negative offsets + || offset < 0 + // don't allow anything with .. path + || strstr( name, ".." ) + // leading dots, slashes, etc are no good + || !Q_ispath( name[0] ) + // trailing dots, slashes, etc are no good + || !Q_ispath( name[ length - 1 ] ) + // back slashes should be never sent + || strchr( name, '\\' ) + // colons are bad also + || strchr( name, ':' ) + // MUST be in a subdirectory + || !strchr( name, '/' ) ) + { + SV_DownloadFailed(); + return; + } + + if( strncmp( name, "players/", 8 ) == 0 ) { + allow = allow_download_players; + } else if( strncmp( name, "models/", 7 ) == 0 ) { + allow = allow_download_models; + } else if( strncmp( name, "sound/", 6 ) == 0 ) { + allow = allow_download_sounds; + } else if( strncmp( name, "maps/", 5 ) == 0 ) { + allow = allow_download_maps; + } else { + allow = allow_download_other; + } + + if( !allow->integer ) { + Com_DPrintf( "Refusing download of %s to %s\n", name, sv_client->name ); + SV_DownloadFailed(); + return; + } + + if( sv_client->download ) { + Com_DPrintf( "Closing existing download for %s (should not happen)\n", sv_client->name ); + FS_FreeFile( sv_client->download ); + sv_client->download = NULL; + } + + filename = name; + + downloadsize = FS_LoadFileEx( filename, NULL, 0, TAG_SERVER ); + + if( downloadsize == INVALID_LENGTH || downloadsize == 0 + // special check for maps, if it came from a pak file, don't allow + // download ZOID + || ( allow == allow_download_maps + && allow_download_maps->integer < 2 + && FS_LastFileFromPak() ) ) + { + Com_DPrintf( "Couldn't download %s to %s\n", name, sv_client->name ); + SV_DownloadFailed(); + return; + } + + if( offset > downloadsize ) { + Com_DPrintf( "Refusing download, %s has wrong version of %s (%d > %d)\n", + sv_client->name, name, offset, downloadsize ); + SV_ClientPrintf( sv_client, PRINT_HIGH, "File size differs from server.\n" + "Please delete the corresponding .tmp file from your system.\n" ); + SV_DownloadFailed(); + return; + } + + if( offset == downloadsize ) { + Com_DPrintf( "Refusing download, %s already has %s (%d bytes)\n", + sv_client->name, name, offset ); + MSG_WriteByte( svc_download ); + MSG_WriteShort( 0 ); + MSG_WriteByte( 100 ); + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + return; + } + + sv_client->downloadsize = FS_LoadFileEx( filename, ( void ** )&sv_client->download, 0, TAG_SERVER ); - sv_client->downloadcount = offset; + sv_client->downloadcount = offset; - Com_DPrintf( "Downloading %s to %s\n", name, sv_client->name ); + Com_DPrintf( "Downloading %s to %s\n", name, sv_client->name ); - SV_NextDownload_f(); + SV_NextDownload_f(); } static void SV_StopDownload_f( void ) { - int size, percent; - - if( !sv_client->download ) { - return; - } - - size = sv_client->downloadsize; - if( !size ) { - percent = 0; - } else { - percent = sv_client->downloadcount*100/size; - } - - MSG_WriteByte( svc_download ); - MSG_WriteShort( -1 ); - MSG_WriteByte( percent ); - SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); - - Com_DPrintf( "Download for %s stopped by user request\n", sv_client->name ); - Z_Free( sv_client->download ); - sv_client->download = NULL; + int size, percent; + + if( !sv_client->download ) { + return; + } + + size = sv_client->downloadsize; + if( !size ) { + percent = 0; + } else { + percent = sv_client->downloadcount*100/size; + } + + MSG_WriteByte( svc_download ); + MSG_WriteShort( -1 ); + MSG_WriteByte( percent ); + SV_ClientAddMessage( sv_client, MSG_RELIABLE|MSG_CLEAR ); + + Com_DPrintf( "Download for %s stopped by user request\n", sv_client->name ); + Z_Free( sv_client->download ); + sv_client->download = NULL; } //============================================================================ @@ -697,7 +706,7 @@ static void SV_Disconnect_f( void ) { Com_Printf( "%s[%s] disconnected\n", sv_client->name, NET_AdrToString( &sv_client->netchan->remote_address ) ); } - SV_DropClient( sv_client, NULL ); + SV_DropClient( sv_client, NULL ); } @@ -713,21 +722,21 @@ static void SV_ShowServerinfo_f( void ) { Cvar_BitInfo( serverinfo, CVAR_SERVERINFO ); - SV_BeginRedirect( RD_CLIENT ); - Info_Print( serverinfo ); - Com_EndRedirect(); + SV_BeginRedirect( RD_CLIENT ); + Info_Print( serverinfo ); + Com_EndRedirect(); } static void SV_NoGameData_f( void ) { - sv_client->flags ^= CF_NODATA; + sv_client->flags ^= CF_NODATA; } static void SV_CvarResult_f( void ) { - char *c, *v; + char *c, *v; - c = Cmd_Argv( 1 ); - if( !strcmp( c, "version" ) ) { - if( !sv_client->versionString ) { + c = Cmd_Argv( 1 ); + if( !strcmp( c, "version" ) ) { + if( !sv_client->versionString ) { v = Cmd_RawArgsFrom( 2 ); if( dedicated->integer ) { Com_Printf( "%s[%s]: %s\n", sv_client->name, @@ -735,7 +744,7 @@ static void SV_CvarResult_f( void ) { } sv_client->versionString = SV_CopyString( v ); } - } else if( !strcmp( c, "connect" ) ) { + } else if( !strcmp( c, "connect" ) ) { if( sv_client->reconnect_var[0] ) { v = Cmd_Argv( 2 ); if( !strcmp( v, sv_client->reconnect_val ) ) { @@ -744,7 +753,7 @@ static void SV_CvarResult_f( void ) { } } #if USE_ANTICHEAT & 2 - else if( !strcmp( c, "actoken" ) ) { + else if( !strcmp( c, "actoken" ) ) { AC_ClientToken( sv_client, Cmd_Argv( 2 ) ); } #endif @@ -753,43 +762,43 @@ static void SV_CvarResult_f( void ) { #if USE_ANTICHEAT & 2 static void SV_AC_List_f( void ) { - SV_BeginRedirect( RD_CLIENT ); - AC_List_f(); - Com_EndRedirect(); + SV_BeginRedirect( RD_CLIENT ); + AC_List_f(); + Com_EndRedirect(); } static void SV_AC_Info_f( void ) { - SV_BeginRedirect( RD_CLIENT ); - AC_Info_f(); - Com_EndRedirect(); + SV_BeginRedirect( RD_CLIENT ); + AC_Info_f(); + Com_EndRedirect(); } #endif static const ucmd_t ucmds[] = { - // auto issued - { "new", SV_New_f }, - { "begin", SV_Begin_f }, - { "baselines", NULL }, - { "configstrings", NULL }, - { "nextserver", NULL }, - { "disconnect", SV_Disconnect_f }, - - // issued by hand at client consoles - { "info", SV_ShowServerinfo_f }, - - { "download", SV_BeginDownload_f }, - { "nextdl", SV_NextDownload_f }, - { "stopdl", SV_StopDownload_f }, - - { "\177c", SV_CvarResult_f }, - { "nogamedata", SV_NoGameData_f }, + // auto issued + { "new", SV_New_f }, + { "begin", SV_Begin_f }, + { "baselines", NULL }, + { "configstrings", NULL }, + { "nextserver", NULL }, + { "disconnect", SV_Disconnect_f }, + + // issued by hand at client consoles + { "info", SV_ShowServerinfo_f }, + + { "download", SV_BeginDownload_f }, + { "nextdl", SV_NextDownload_f }, + { "stopdl", SV_StopDownload_f }, + + { "\177c", SV_CvarResult_f }, + { "nogamedata", SV_NoGameData_f }, #if USE_ANTICHEAT & 2 - { "aclist", SV_AC_List_f }, - { "acinfo", SV_AC_Info_f }, + { "aclist", SV_AC_List_f }, + { "acinfo", SV_AC_Info_f }, #endif - { NULL, NULL } + { NULL, NULL } }; /* @@ -798,16 +807,16 @@ SV_ExecuteUserCommand ================== */ static void SV_ExecuteUserCommand( const char *s ) { - const ucmd_t *u; - char *c; - - Cmd_TokenizeString( s, qfalse ); - sv_player = sv_client->edict; + const ucmd_t *u; + char *c; + + Cmd_TokenizeString( s, qfalse ); + sv_player = sv_client->edict; - c = Cmd_Argv( 0 ); - if( !c[0] ) { - return; - } + c = Cmd_Argv( 0 ); + if( !c[0] ) { + return; + } if( ( u = Com_Find( ucmds, c ) ) != NULL ) { if( u->func ) { @@ -835,17 +844,17 @@ SV_ClientThink ================== */ static inline void SV_ClientThink( client_t *cl, usercmd_t *cmd ) { - cl->commandMsec -= cmd->msec; + cl->commandMsec -= cmd->msec; - if( cl->commandMsec < 0 && sv_enforcetime->integer ) { + if( cl->commandMsec < 0 && sv_enforcetime->integer ) { #ifdef _DEBUG - Com_DPrintf( "commandMsec underflow from %s: %d\n", - cl->name, cl->commandMsec ); + Com_DPrintf( "commandMsec underflow from %s: %d\n", + cl->name, cl->commandMsec ); #endif - return; - } + return; + } - ge->ClientThink( cl->edict, cmd ); + ge->ClientThink( cl->edict, cmd ); } static inline void SV_SetLastFrame( int lastframe ) { @@ -871,17 +880,17 @@ SV_OldClientExecuteMove ================== */ static void SV_OldClientExecuteMove( int net_drop ) { - usercmd_t oldest, oldcmd, newcmd; - int lastframe; + usercmd_t oldest, oldcmd, newcmd; + int lastframe; - if( sv_client->protocol == PROTOCOL_VERSION_DEFAULT ) { - MSG_ReadByte(); // skip over checksum - } - + if( sv_client->protocol == PROTOCOL_VERSION_DEFAULT ) { + MSG_ReadByte(); // skip over checksum + } + lastframe = MSG_ReadLong(); SV_SetLastFrame( lastframe ); - if( sv_client->protocol == PROTOCOL_VERSION_R1Q2 && + if( sv_client->protocol == PROTOCOL_VERSION_R1Q2 && sv_client->version >= PROTOCOL_VERSION_R1Q2_UCMD ) { MSG_ReadDeltaUsercmd_Hacked( NULL, &oldest ); @@ -893,31 +902,31 @@ static void SV_OldClientExecuteMove( int net_drop ) { MSG_ReadDeltaUsercmd( &oldcmd, &newcmd ); } - if( sv_client->state != cs_spawned ) { - sv_client->lastframe = -1; - return; - } + if( sv_client->state != cs_spawned ) { + sv_client->lastframe = -1; + return; + } - if( net_drop > 2 ) { + if( net_drop > 2 ) { sv_client->frameflags |= FF_CLIENTPRED; -// Com_DPrintf( "%s: net_drop %i\n", sv_client->name, net_drop ); - } - - if( net_drop < 20 ) { - while( net_drop > 2 ) { - SV_ClientThink( sv_client, &sv_client->lastcmd ); - net_drop--; - } - if( net_drop > 1 ) - SV_ClientThink( sv_client, &oldest ); - - if( net_drop > 0 ) - SV_ClientThink( sv_client, &oldcmd ); - - } - SV_ClientThink( sv_client, &newcmd ); - - sv_client->lastcmd = newcmd; +// Com_DPrintf( "%s: net_drop %i\n", sv_client->name, net_drop ); + } + + if( net_drop < 20 ) { + while( net_drop > 2 ) { + SV_ClientThink( sv_client, &sv_client->lastcmd ); + net_drop--; + } + if( net_drop > 1 ) + SV_ClientThink( sv_client, &oldest ); + + if( net_drop > 0 ) + SV_ClientThink( sv_client, &oldcmd ); + + } + SV_ClientThink( sv_client, &newcmd ); + + sv_client->lastcmd = newcmd; } @@ -928,91 +937,91 @@ SV_NewClientExecuteMove ================== */ static void SV_NewClientExecuteMove( int c, int net_drop ) { - 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; - - numDups = c >> SVCMD_BITS; - c &= SVCMD_MASK; - - if( numDups >= MAX_PACKET_FRAMES ) { - SV_DropClient( sv_client, "too many frames in packet" ); - return; - } - - if( c == clc_move_nodelta ) { - lastframe = -1; - } else { - lastframe = MSG_ReadLong(); - } + 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; + + numDups = c >> SVCMD_BITS; + c &= SVCMD_MASK; + + if( numDups >= MAX_PACKET_FRAMES ) { + SV_DropClient( sv_client, "too many frames in packet" ); + return; + } + + if( c == clc_move_nodelta ) { + lastframe = -1; + } else { + lastframe = MSG_ReadLong(); + } SV_SetLastFrame( lastframe ); - lightlevel = MSG_ReadByte(); - - // read all cmds - lastcmd = NULL; - for( i = 0; i <= numDups; i++ ) { - numCmds[i] = MSG_ReadBits( 5 ); - if( numCmds[i] == -1 ) { - SV_DropClient( sv_client, "read past end of message" ); - return; - } - if( numCmds[i] >= MAX_PACKET_USERCMDS ) { - SV_DropClient( sv_client, "too many usercmds in frame" ); - return; - } - for( j = 0; j < numCmds[i]; j++ ) { - if( msg_read.readcount > msg_read.cursize ) { - SV_DropClient( sv_client, "read past end of message" ); - return; - } - cmd = &cmds[i][j]; - MSG_ReadDeltaUsercmd_Enhanced( lastcmd, cmd, sv_client->version ); - cmd->lightlevel = lightlevel; - lastcmd = cmd; - } - } - if( sv_client->state != cs_spawned ) { - sv_client->lastframe = -1; - return; - } - - if( q_unlikely( !lastcmd ) ) { - return; // should never happen - } - - if( net_drop > numDups ) { + lightlevel = MSG_ReadByte(); + + // read all cmds + lastcmd = NULL; + for( i = 0; i <= numDups; i++ ) { + numCmds[i] = MSG_ReadBits( 5 ); + if( numCmds[i] == -1 ) { + SV_DropClient( sv_client, "read past end of message" ); + return; + } + if( numCmds[i] >= MAX_PACKET_USERCMDS ) { + SV_DropClient( sv_client, "too many usercmds in frame" ); + return; + } + for( j = 0; j < numCmds[i]; j++ ) { + if( msg_read.readcount > msg_read.cursize ) { + SV_DropClient( sv_client, "read past end of message" ); + return; + } + cmd = &cmds[i][j]; + MSG_ReadDeltaUsercmd_Enhanced( lastcmd, cmd, sv_client->version ); + cmd->lightlevel = lightlevel; + lastcmd = cmd; + } + } + if( sv_client->state != cs_spawned ) { + sv_client->lastframe = -1; + return; + } + + if( q_unlikely( !lastcmd ) ) { + return; // should never happen + } + + if( net_drop > numDups ) { sv_client->frameflags |= FF_CLIENTPRED; -// Com_DPrintf( "%s: net_drop %i\n", sv_client->name, net_drop ); - } - - if( net_drop < 20 ) { - // run lastcmd multiple times if no backups available - while( net_drop > numDups ) { - SV_ClientThink( sv_client, &sv_client->lastcmd ); - net_drop--; - } - - // run backup cmds, if any - while( net_drop > 0 ) { - i = numDups - net_drop; - for( j = 0; j < numCmds[i]; j++ ) { - SV_ClientThink( sv_client, &cmds[i][j] ); - } - net_drop--; - } - - } - - // run new cmds - for( j = 0; j < numCmds[numDups]; j++ ) { - SV_ClientThink( sv_client, &cmds[numDups][j] ); - } - - sv_client->lastcmd = *lastcmd; +// Com_DPrintf( "%s: net_drop %i\n", sv_client->name, net_drop ); + } + + if( net_drop < 20 ) { + // run lastcmd multiple times if no backups available + while( net_drop > numDups ) { + SV_ClientThink( sv_client, &sv_client->lastcmd ); + net_drop--; + } + + // run backup cmds, if any + while( net_drop > 0 ) { + i = numDups - net_drop; + for( j = 0; j < numCmds[i]; j++ ) { + SV_ClientThink( sv_client, &cmds[i][j] ); + } + net_drop--; + } + + } + + // run new cmds + for( j = 0; j < numCmds[numDups]; j++ ) { + SV_ClientThink( sv_client, &cmds[numDups][j] ); + } + + sv_client->lastcmd = *lastcmd; } /* @@ -1023,153 +1032,151 @@ The current net_message is parsed for the given client =================== */ void SV_ExecuteClientMessage( client_t *client ) { - int c; - char *s; - qboolean move_issued; - int stringCmdCount; - int userinfoUpdateCount; - int net_drop; - - sv_client = client; - sv_player = sv_client->edict; - - // only allow one move command - move_issued = qfalse; - stringCmdCount = 0; - userinfoUpdateCount = 0; - - net_drop = client->netchan->dropped; + int c; + char *s; + qboolean move_issued; + int stringCmdCount; + int userinfoUpdateCount; + int net_drop; + + sv_client = client; + sv_player = sv_client->edict; + + // only allow one move command + move_issued = 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" ); - break; - } - - c = MSG_ReadByte(); - if( c == -1 ) - break; - - switch( c & SVCMD_MASK ) { - default: - badbyte: - SV_DropClient( client, "unknown command byte" ); - break; - - case clc_nop: - break; - - case clc_userinfo: - s = MSG_ReadString(); - - // malicious users may try sending too many userinfo updates - if( userinfoUpdateCount == MAX_PACKET_USERINFOS ) { - Com_DPrintf( "Too many userinfos from %s\n", client->name ); - break; - } - - SV_UpdateUserinfo( s ); - userinfoUpdateCount++; - 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 ); - break; - - case clc_stringcmd: - s = MSG_ReadString(); - - Com_DPrintf( "ClientCommand( %s ): %s\n", client->name, s ); - - // 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( s ); - stringCmdCount++; - break; - - // r1q2 specific operations - case clc_setting: { - uint16_t idx, value; - - if( client->protocol < PROTOCOL_VERSION_R1Q2 ) { - goto badbyte; - } - - idx = MSG_ReadShort(); - value = MSG_ReadShort(); - if( idx < CLS_MAX ) { - client->settings[idx] = value; - } - } - break; - - - // q2pro specific operations - case clc_move_nodelta: - case clc_move_batched: - 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 ); - break; - - case clc_userinfo_delta: { - char *key, *value; - char buffer[MAX_INFO_STRING]; - - if( client->protocol != PROTOCOL_VERSION_Q2PRO ) { - goto badbyte; - } - - key = MSG_ReadString(); - value = MSG_ReadString(); - - // malicious users may try sending too many userinfo updates - if( userinfoUpdateCount == MAX_PACKET_USERINFOS ) { - Com_DPrintf( "Too many userinfos from %s\n", client->name ); - break; - } - userinfoUpdateCount++; - - strcpy( buffer, client->userinfo ); - if( !Info_SetValueForKey( buffer, key, value ) ) { - SV_DropClient( client, "malformed delta userinfo" ); - break; - } - - SV_UpdateUserinfo( buffer ); - } - break; - } - - if( client->state < cs_assigned ) { - break; // disconnect command - } - } - - sv_client = NULL; - sv_player = NULL; -} + while( 1 ) { + if( msg_read.readcount > msg_read.cursize ) { + SV_DropClient( client, "read past end of message" ); + break; + } + + c = MSG_ReadByte(); + if( c == -1 ) + break; + + switch( c & SVCMD_MASK ) { + default: + badbyte: + SV_DropClient( client, "unknown command byte" ); + break; + + case clc_nop: + break; + + case clc_userinfo: + s = MSG_ReadString(); + + // malicious users may try sending too many userinfo updates + if( userinfoUpdateCount == MAX_PACKET_USERINFOS ) { + Com_DPrintf( "Too many userinfos from %s\n", client->name ); + break; + } + + SV_UpdateUserinfo( s ); + userinfoUpdateCount++; + 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 ); + break; + + case clc_stringcmd: + s = MSG_ReadString(); + + Com_DPrintf( "ClientCommand( %s ): %s\n", client->name, s ); + + // 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( s ); + stringCmdCount++; + break; + + // r1q2 specific operations + case clc_setting: { + uint16_t idx, value; + + if( client->protocol < PROTOCOL_VERSION_R1Q2 ) { + goto badbyte; + } + idx = MSG_ReadShort(); + value = MSG_ReadShort(); + if( idx < CLS_MAX ) { + client->settings[idx] = value; + } + } + break; + + + // q2pro specific operations + case clc_move_nodelta: + case clc_move_batched: + 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 ); + break; + + case clc_userinfo_delta: { + char *key, *value; + char buffer[MAX_INFO_STRING]; + + if( client->protocol != PROTOCOL_VERSION_Q2PRO ) { + goto badbyte; + } + + key = MSG_ReadString(); + value = MSG_ReadString(); + // malicious users may try sending too many userinfo updates + if( userinfoUpdateCount == MAX_PACKET_USERINFOS ) { + Com_DPrintf( "Too many userinfos from %s\n", client->name ); + break; + } + userinfoUpdateCount++; + + strcpy( buffer, client->userinfo ); + if( !Info_SetValueForKey( buffer, key, value ) ) { + SV_DropClient( client, "malformed delta userinfo" ); + break; + } + + SV_UpdateUserinfo( buffer ); + } + break; + } + + if( client->state < cs_assigned ) { + break; // disconnect command + } + } + + sv_client = NULL; + sv_player = NULL; +} |