diff options
-rw-r--r-- | source/cl_parse.c | 18 | ||||
-rw-r--r-- | source/mvd_client.c | 89 | ||||
-rw-r--r-- | source/mvd_gtv.h (renamed from source/gtv.h) | 0 | ||||
-rw-r--r-- | source/mvd_local.h | 12 | ||||
-rw-r--r-- | source/mvd_parse.c | 4 | ||||
-rw-r--r-- | source/net_common.c | 8 | ||||
-rw-r--r-- | source/protocol.h | 11 | ||||
-rw-r--r-- | source/sv_ac.c | 452 | ||||
-rw-r--r-- | source/sv_mvd.c | 12 | ||||
-rw-r--r-- | source/sv_world.c | 16 |
10 files changed, 334 insertions, 288 deletions
diff --git a/source/cl_parse.c b/source/cl_parse.c index b5f2b08..b6c9206 100644 --- a/source/cl_parse.c +++ b/source/cl_parse.c @@ -1051,13 +1051,13 @@ CL_ParseStartSoundPacket */ static void CL_ParseStartSoundPacket( void ) { vec3_t pos_v; - float *pos; + float *pos; int channel, ent; int sound_num; - float volume; - float attenuation; - int flags; - float ofs; + float volume; + float attenuation; + int flags; + float ofs; flags = MSG_ReadByte(); sound_num = MSG_ReadByte(); @@ -1312,9 +1312,9 @@ static void CL_ParseInventory( void ) { static void CL_ParseZPacket( void ) { #if USE_ZLIB - sizebuf_t temp; + sizebuf_t temp; byte buffer[MAX_MSGLEN]; - unsigned inlen, outlen; + size_t inlen, outlen; if( msg_read.data != msg_read_buffer ) { Com_Error( ERR_DROP, "%s: recursively entered", __func__ ); @@ -1333,9 +1333,9 @@ static void CL_ParseZPacket( void ) { inflateReset( &cls.z ); cls.z.next_in = msg_read.data + msg_read.readcount; - cls.z.avail_in = inlen; + cls.z.avail_in = ( uInt )inlen; cls.z.next_out = buffer; - cls.z.avail_out = outlen; + cls.z.avail_out = ( uInt )outlen; if( inflate( &cls.z, Z_FINISH ) != Z_STREAM_END ) { Com_Error( ERR_DROP, "%s: inflate() failed: %s", __func__, cls.z.msg ); } diff --git a/source/mvd_client.c b/source/mvd_client.c index 3ace856..6b6c45d 100644 --- a/source/mvd_client.c +++ b/source/mvd_client.c @@ -24,11 +24,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sv_local.h" #include "mvd_local.h" -#include "gtv.h" +#include "mvd_gtv.h" #include <setjmp.h> -#define GTV_DEFAULT_BACKOFF (5*1000) -#define GTV_MAXIMUM_BACKOFF (5*3600*1000) +#define GTV_DEFAULT_BACKOFF (5*1000) // 5 seconds +#define GTV_MAXIMUM_BACKOFF (5*3600*1000) // 5 hours + +#define GTV_PING_INTERVAL (60*1000) // 1 minute typedef enum { GTV_DISCONNECTED, // disconnected @@ -82,7 +84,8 @@ static const char *const gtv_states[GTV_NUM_STATES] = { "preparing", "connected", "resuming", - "active", + "waiting", + "reading", "suspending" }; @@ -555,6 +558,27 @@ GTV CONNECTIONS ==================================================================== */ +static void write_stream( gtv_t *gtv, void *data, size_t len ) { + if( FIFO_Write( >v->stream.send, data, len ) != len ) { + gtv_destroyf( gtv, "Send buffer overflowed" ); + } + + // don't timeout + gtv->last_sent = svs.realtime; +} + +static void write_message( gtv_t *gtv, gtv_clientop_t op ) { + byte header[3]; + size_t len = msg_write.cursize + 1; + + header[0] = len & 255; + header[1] = ( len >> 8 ) & 255; + header[2] = op; + write_stream( gtv, header, sizeof( header ) ); + + write_stream( gtv, msg_write.data, msg_write.cursize ); +} + static qboolean gtv_wait_stop( mvd_t *mvd ) { int usage; @@ -605,6 +629,9 @@ static void gtv_wait_start( mvd_t *mvd ) { MVD_BroadcastPrintf( mvd, PRINT_HIGH, 0, "[MVD] Buffering data, please wait...\n" ); } + + // send ping to force server to flush + write_message( gtv, GTC_PING ); } else { // this is a `normal' underflow, reset delay to default mvd->min_packets = tr; @@ -659,27 +686,6 @@ static qboolean gtv_read_frame( mvd_t *mvd ) { return qtrue; } -static void write_stream( gtv_t *gtv, void *data, size_t len ) { - if( FIFO_Write( >v->stream.send, data, len ) != len ) { - gtv_destroyf( gtv, "Send buffer overflowed" ); - } - - // don't timeout - gtv->last_sent = svs.realtime; -} - -static void write_message( gtv_t *gtv, gtv_clientop_t op ) { - byte header[3]; - size_t len = msg_write.cursize + 1; - - header[0] = len & 255; - header[1] = ( len >> 8 ) & 255; - header[2] = op; - write_stream( gtv, header, sizeof( header ) ); - - write_stream( gtv, msg_write.data, msg_write.cursize ); -} - static qboolean gtv_forward_cmd( mvd_client_t *client ) { mvd_t *mvd = client->mvd; gtv_t *gtv = mvd->gtv; @@ -741,9 +747,9 @@ static void send_stream_start( gtv_t *gtv ) { int maxbuf; if( gtv->mvd ) { - maxbuf = gtv->mvd->min_packets - 10; + maxbuf = gtv->mvd->min_packets / 2; } else { - maxbuf = mvd_wait_delay->value * 10 - 10; + maxbuf = mvd_wait_delay->value * 10 / 2; } if( maxbuf < 10 ) { maxbuf = 10; @@ -980,10 +986,6 @@ static qboolean parse_message( gtv_t *gtv, fifo_t *fifo ) { cmd = MSG_ReadByte(); - if( mvd_shownet->integer == -1 ) { - Com_Printf( "[%"PRIz"]%d ", msg_read.cursize, cmd ); - } - switch( cmd ) { case GTS_HELLO: parse_hello( gtv ); @@ -1107,27 +1109,40 @@ static neterr_t run_connect( gtv_t *gtv ) { static neterr_t run_stream( gtv_t *gtv ) { neterr_t ret; + int count; + size_t usage; // run network stream if( ( ret = NET_RunStream( >v->stream ) ) != NET_OK ) { return ret; } + count = 0; + usage = FIFO_Usage( >v->stream.recv ); + #if USE_ZLIB if( gtv->z_act ) { - do { + while( 1 ) { // decompress more data if( gtv->z_act ) { inflate_more( gtv ); } - } while( parse_message( gtv, >v->z_buf ) ); + if( !parse_message( gtv, >v->z_buf ) ) { + break; + } + count++; + } } else #endif - while( parse_message( gtv, >v->stream.recv ) ) - ; + while( parse_message( gtv, >v->stream.recv ) ) { + count++; + } if( mvd_shownet->integer == -1 ) { - Com_Printf( "\n" ); + size_t total = usage - FIFO_Usage( >v->stream.recv ); + + Com_Printf( "[%s] %"PRIz" bytes, %d msgs\n", + gtv->name, total, count ); } return NET_OK; @@ -1155,7 +1170,7 @@ static void check_timeouts( gtv_t *gtv ) { } // ping if no data has been sent for too long - if( svs.realtime - gtv->last_sent > 60000 ) { + if( svs.realtime - gtv->last_sent > GTV_PING_INTERVAL ) { write_message( gtv, GTC_PING ); } } diff --git a/source/gtv.h b/source/mvd_gtv.h index cac7567..cac7567 100644 --- a/source/gtv.h +++ b/source/mvd_gtv.h diff --git a/source/mvd_local.h b/source/mvd_local.h index 74078fb..2442a1d 100644 --- a/source/mvd_local.h +++ b/source/mvd_local.h @@ -91,8 +91,8 @@ typedef struct { #define MAX_MVD_NAME 16 typedef enum { - MVD_DEAD, // no gamestate received yet, unusable - MVD_WAITING, // buffering more frames + MVD_DEAD, // no gamestate received yet, unusable for observers + MVD_WAITING, // buffering more frames, stalled MVD_READING, // reading frames MVD_NUM_STATES @@ -100,6 +100,8 @@ typedef enum { struct gtv_s; +// FIXME: entire struct is > 400 K in size! +// need to eliminate those large static arrays below... typedef struct mvd_s { list_t entry; list_t active; @@ -131,13 +133,13 @@ typedef struct mvd_s { vec3_t spawnOrigin; vec3_t spawnAngles; int pm_type; - char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH]; - edict_t edicts[MAX_EDICTS]; + char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH]; // 133 K + edict_t edicts[MAX_EDICTS]; // 266 K mvd_player_t *players; // [maxclients] mvd_player_t *dummy; // &players[clientNum] int numplayers; // number of active players in frame int clientNum; - int flags; + mvd_flags_t flags; char layout[MAX_STRING_CHARS]; char oldscores[MAX_STRING_CHARS]; // layout is copied here qboolean intermission; diff --git a/source/mvd_parse.c b/source/mvd_parse.c index 0045bc9..a0f9070 100644 --- a/source/mvd_parse.c +++ b/source/mvd_parse.c @@ -380,7 +380,7 @@ static void MVD_UnicastPrint( mvd_t *mvd, qboolean reliable, mvd_player_t *playe continue; } // decide if message should be routed or not - target = ( mvd->flags & 1 ) ? mvd->dummy : + target = ( mvd->flags & MVF_NOMSGS ) ? mvd->dummy : client->target ? client->target : mvd->dummy; if( target == player ) { cl->AddMessage( cl, data, length, reliable ); @@ -1166,6 +1166,8 @@ void MVD_ParseMessage( mvd_t *mvd ) { case mvd_print: MVD_ParsePrint( mvd ); break; + case mvd_nop: + break; default: MVD_Destroyf( mvd, "Illegible command at %"PRIz": %d", msg_read.readcount - 1, cmd ); diff --git a/source/net_common.c b/source/net_common.c index 900b2aa..860eff8 100644 --- a/source/net_common.c +++ b/source/net_common.c @@ -37,7 +37,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include <windows.h> #include <winsock2.h> #define socklen_t int -#define NET_GET_ERROR() do { net_error = WSAGetLastError(); } while( 0 ) +#define NET_GET_ERROR() ( net_error = WSAGetLastError() ) #elif defined( __unix__ ) #include <unistd.h> #include <sys/socket.h> @@ -53,7 +53,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define INVALID_SOCKET -1 #define closesocket close #define ioctlsocket ioctl -#define NET_GET_ERROR() do { net_error = errno; } while( 0 ) +#define NET_GET_ERROR() ( net_error = errno ) #else #error Unknown target OS #endif @@ -822,7 +822,6 @@ neterr_t NET_Listen( qboolean arg ) { return NET_OK; } - // zero TCP port means use default server port tcp_socket = TCP_OpenSocket( net_tcp_ip->string, net_tcp_port->integer, NS_SERVER ); if( tcp_socket == INVALID_SOCKET ) { @@ -995,6 +994,7 @@ error2: return NET_ERROR; } +// returns NET_OK only when there was some data read neterr_t NET_RunStream( netstream_t *s ) { struct timeval tv; fd_set rfd, wfd; @@ -1064,7 +1064,7 @@ neterr_t NET_RunStream( netstream_t *s ) { } net_sent += ret; - result = NET_OK; + //result = NET_OK; } } diff --git a/source/protocol.h b/source/protocol.h index 517e6ce..68fba83 100644 --- a/source/protocol.h +++ b/source/protocol.h @@ -140,7 +140,7 @@ typedef enum mvd_ops_e { mvd_serverdata, mvd_configstring, mvd_frame, - mvd_frame_nodelta, + mvd_frame_nodelta, // reserved mvd_unicast, mvd_unicast_r, mvd_multicast_all, @@ -150,12 +150,19 @@ typedef enum mvd_ops_e { mvd_multicast_pvs_r, mvd_multicast_phs_r, mvd_sound, - mvd_print, // reserved + mvd_print, mvd_stufftext, // reserved mvd_num_types } mvd_ops_t; +// MVD stream flags (only 3 bits can be used) +typedef enum { + MVF_NOMSGS = 1, + MVF_RESERVED1 = 2, + MVF_RESERVED2 = 4 +} mvd_flags_t; + //============================================== // diff --git a/source/sv_ac.c b/source/sv_ac.c index 4de9da4..b3ac447 100644 --- a/source/sv_ac.c +++ b/source/sv_ac.c @@ -26,42 +26,42 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sv_local.h" typedef enum { - ACS_BAD, - ACS_CLIENTACK, - ACS_VIOLATION, - ACS_NOACCESS, - ACS_FILE_VIOLATION, - ACS_READY, - ACS_QUERYREPLY, - ACS_PONG, - ACS_UPDATE_REQUIRED, - ACS_DISCONNECT, - ACS_ERROR + ACS_BAD, + ACS_CLIENTACK, + ACS_VIOLATION, + ACS_NOACCESS, + ACS_FILE_VIOLATION, + ACS_READY, + ACS_QUERYREPLY, + ACS_PONG, + ACS_UPDATE_REQUIRED, + ACS_DISCONNECT, + ACS_ERROR } ac_serverbyte_t; typedef enum { - ACC_BAD, - ACC_VERSION, - ACC_PREF, - ACC_REQUESTCHALLENGE, - ACC_CLIENTDISCONNECT, - ACC_QUERYCLIENT, - ACC_PING, - ACC_UPDATECHECKS, - ACC_SETPREFERENCES + ACC_BAD, + ACC_VERSION, + ACC_PREF, + ACC_REQUESTCHALLENGE, + ACC_CLIENTDISCONNECT, + ACC_QUERYCLIENT, + ACC_PING, + ACC_UPDATECHECKS, + ACC_SETPREFERENCES } ac_clientbyte_t; typedef enum { - OP_INVALID, - OP_EQUAL, - OP_NEQUAL, - OP_GTEQUAL, - OP_LTEQUAL, - OP_LT, - OP_GT, - OP_STREQUAL, - OP_STRNEQUAL, - OP_STRSTR + OP_INVALID, + OP_EQUAL, + OP_NEQUAL, + OP_GTEQUAL, + OP_LTEQUAL, + OP_LT, + OP_GT, + OP_STREQUAL, + OP_STRNEQUAL, + OP_STRSTR } ac_opcode_t; typedef enum { @@ -111,12 +111,12 @@ typedef struct { char hashlist_name[MAX_QPATH]; } ac_static_t; -#define ACP_BLOCKPLAY ( 1 << 0 ) +#define ACP_BLOCKPLAY ( 1 << 0 ) -#define ACH_REQUIRED ( 1 << 0 ) -#define ACH_NEGATIVE ( 1 << 1 ) +#define ACH_REQUIRED ( 1 << 0 ) +#define ACH_NEGATIVE ( 1 << 1 ) -#define AC_PROTOCOL_VERSION 0xAC03 +#define AC_PROTOCOL_VERSION 0xAC03 #define AC_DEFAULT_BACKOFF 30 @@ -272,7 +272,7 @@ static void AC_ParseCvar( const char *data, int linenum, const char *path ) { ac_cvar_t *cvar; const ac_cvarop_t *op; int i; - size_t len; + size_t len; name = COM_SimpleParse( &data, &namelen ); if( !name[0] ) { @@ -478,7 +478,7 @@ static void AC_Drop( void ) { NET_Close( &ac.stream ); if( !ac.connected ) { - Com_Printf( "ANTICHEAT: Server connection failed. " + Com_Printf( "ANTICHEAT: Server connection failed. " "Retrying in %d seconds.\n", acs.retry_backoff ); clock = time( NULL ); acs.retry_time = clock + acs.retry_backoff; @@ -491,23 +491,23 @@ static void AC_Drop( void ) { cl->ac_file_failures = 0; } - // inform - if( ac.ready ) { - SV_BroadcastPrintf( PRINT_HIGH, AC_MESSAGE + // inform + if( ac.ready ) { + SV_BroadcastPrintf( PRINT_HIGH, AC_MESSAGE "This server has lost the connection to the anticheat server. " "Any anticheat clients are no longer valid.\n" ); - if( ac_required->integer == 2 ) { - SV_BroadcastPrintf( PRINT_HIGH, AC_MESSAGE + if( ac_required->integer == 2 ) { + SV_BroadcastPrintf( PRINT_HIGH, AC_MESSAGE "You will need to reconnect once the server has " "re-established the anticheat connection.\n" ); } acs.retry_backoff = AC_DEFAULT_BACKOFF; - } else { + } else { acs.retry_backoff += 30; // this generally indicates a server problem } - Com_WPrintf( + Com_WPrintf( "ANTICHEAT: Lost connection to anticheat server! " "Will attempt to reconnect in %d seconds.\n", acs.retry_backoff ); @@ -524,23 +524,23 @@ static void AC_Disable( void ) { static void AC_Announce( client_t *client, const char *fmt, ... ) { - va_list argptr; - char string[MAX_STRING_CHARS]; + va_list argptr; + char string[MAX_STRING_CHARS]; size_t len; - - va_start( argptr, fmt ); - len = Q_vsnprintf( string, sizeof( string ), fmt, argptr ); - va_end( argptr ); + + va_start( argptr, fmt ); + len = Q_vsnprintf( string, sizeof( string ), fmt, argptr ); + va_end( argptr ); if( len >= sizeof( string ) ) { Com_WPrintf( "%s: overflow\n", __func__ ); return; } - MSG_WriteByte( svc_print ); - MSG_WriteByte( PRINT_HIGH ); - MSG_WriteData( AC_MESSAGE, sizeof( AC_MESSAGE ) - 1 ); - MSG_WriteData( string, len + 1 ); + MSG_WriteByte( svc_print ); + MSG_WriteByte( PRINT_HIGH ); + MSG_WriteData( AC_MESSAGE, sizeof( AC_MESSAGE ) - 1 ); + MSG_WriteData( string, len + 1 ); if( client->state == cs_spawned ) { FOR_EACH_CLIENT( client ) { @@ -552,13 +552,13 @@ static void AC_Announce( client_t *client, const char *fmt, ... ) { SV_ClientAddMessage( client, MSG_RELIABLE ); } - SZ_Clear( &msg_write ); + SZ_Clear( &msg_write ); } static client_t *AC_ParseClient( void ) { client_t *cl; - uint16_t clientID; - uint32_t challenge; + unsigned clientID; + unsigned challenge; if( msg_read.readcount + 6 > msg_read.cursize ) { Com_DPrintf( "ANTICHEAT: Message too short in %s\n", __func__ ); @@ -566,22 +566,22 @@ static client_t *AC_ParseClient( void ) { } clientID = MSG_ReadWord(); - challenge = MSG_ReadLong(); + challenge = MSG_ReadLong(); - if( clientID >= sv_maxclients->integer ) { - Com_WPrintf( "ANTICHEAT: Illegal client ID: %u\n", clientID ); - return NULL; - } + if( clientID >= sv_maxclients->integer ) { + Com_WPrintf( "ANTICHEAT: Illegal client ID: %u\n", clientID ); + return NULL; + } - cl = &svs.udp_client_pool[clientID]; + cl = &svs.udp_client_pool[clientID]; - // we check challenge to ensure we don't get + // we check challenge to ensure we don't get // a race condition if a client reconnects. - if( cl->challenge != challenge ) { - return NULL; + if( cl->challenge != challenge ) { + return NULL; } - if( cl->state < cs_assigned ) { + if( cl->state < cs_assigned ) { return NULL; } @@ -589,8 +589,8 @@ static client_t *AC_ParseClient( void ) { } static void AC_ParseViolation( void ) { - client_t *cl; - char reason[32]; + client_t *cl; + char reason[32]; char clientreason[64]; cl = AC_ParseClient(); @@ -603,12 +603,12 @@ static void AC_ParseViolation( void ) { return; } - MSG_ReadString( reason, sizeof( reason ) ); + MSG_ReadString( reason, sizeof( reason ) ); - if( msg_read.readcount < msg_read.cursize ) { - MSG_ReadString( clientreason, sizeof( clientreason ) ); + if( msg_read.readcount < msg_read.cursize ) { + MSG_ReadString( clientreason, sizeof( clientreason ) ); } else { - clientreason[0] = 0; + clientreason[0] = 0; } // FIXME: should we notify other players about anticheat violations @@ -619,7 +619,7 @@ static void AC_ParseViolation( void ) { // fixme maybe if( strcmp( reason, "disconnected" ) ) { - char showreason[32]; + char showreason[32]; if( ac_show_violation_reason->integer ) Q_snprintf( showreason, sizeof( showreason ), " (%s)", reason ); @@ -661,7 +661,7 @@ static void AC_ParseViolation( void ) { } static void AC_ParseClientAck( void ) { - client_t *cl; + client_t *cl; cl = AC_ParseClient(); if( !cl ) { @@ -673,25 +673,25 @@ static void AC_ParseClientAck( void ) { return; } - if( cl->state > cs_primed ) { - Com_DPrintf( "ANTICHEAT: %s with client in state %d\n", + if( cl->state > cs_primed ) { + Com_DPrintf( "ANTICHEAT: %s with client in state %d\n", __func__, cl->state ); - return; - } + return; + } Com_DPrintf( "ANTICHEAT: %s for %s\n", __func__, cl->name ); - cl->ac_client_type = MSG_ReadByte(); - cl->ac_valid = qtrue; + cl->ac_client_type = MSG_ReadByte(); + cl->ac_valid = qtrue; } static void AC_ParseFileViolation( void ) { - string_entry_t *bad; - client_t *cl; - char path[MAX_QPATH]; + string_entry_t *bad; + client_t *cl; + char path[MAX_QPATH]; char hash[MAX_QPATH]; - int action; - size_t pathlen; - ac_file_t *f; + int action; + size_t pathlen; + ac_file_t *f; cl = AC_ParseClient(); if( !cl ) { @@ -703,16 +703,16 @@ static void AC_ParseFileViolation( void ) { return; } - pathlen = MSG_ReadString( path, sizeof( path ) ); + pathlen = MSG_ReadString( path, sizeof( path ) ); if( pathlen >= sizeof( path ) ) { Com_WPrintf( "ANTICHEAT: Oversize path in %s\n", __func__ ); pathlen = sizeof( path ) - 1; } - if( msg_read.readcount < msg_read.cursize ) { - MSG_ReadString( hash, sizeof( hash ) ); + if( msg_read.readcount < msg_read.cursize ) { + MSG_ReadString( hash, sizeof( hash ) ); } else { - strcpy( hash, "no hash?" ); + strcpy( hash, "no hash?" ); } cl->ac_file_failures++; @@ -767,17 +767,17 @@ static void AC_ParseFileViolation( void ) { } static void AC_ParseReady( void ) { - ac.ready = qtrue; + ac.ready = qtrue; ac.last_ping = svs.realtime; - acs.retry_backoff = AC_DEFAULT_BACKOFF; - Com_Printf( "ANTICHEAT: Ready to serve anticheat clients.\n" ); - Cvar_FullSet( "anticheat", ac_required->string, + acs.retry_backoff = AC_DEFAULT_BACKOFF; + Com_Printf( "ANTICHEAT: Ready to serve anticheat clients.\n" ); + Cvar_FullSet( "anticheat", ac_required->string, CVAR_SERVERINFO | CVAR_NOSET, CVAR_SET_DIRECT ); } static void AC_ParseQueryReply( void ) { - client_t *cl; - int type, valid; + client_t *cl; + int type, valid; cl = AC_ParseClient(); if( !cl ) { @@ -790,27 +790,27 @@ static void AC_ParseQueryReply( void ) { } valid = MSG_ReadByte(); - type = MSG_ReadByte(); + type = MSG_ReadByte(); - cl->ac_query_sent = AC_QUERY_DONE; - if( valid == 1 ) { - cl->ac_client_type = type; - cl->ac_valid = qtrue; - } + cl->ac_query_sent = AC_QUERY_DONE; + if( valid == 1 ) { + cl->ac_client_type = type; + cl->ac_valid = qtrue; + } - if( cl->state < cs_connected || cl->state > cs_primed ) { - Com_WPrintf( "ANTICHEAT: %s with client in state %d\n", + if( cl->state < cs_connected || cl->state > cs_primed ) { + Com_WPrintf( "ANTICHEAT: %s with client in state %d\n", __func__, cl->state ); - SV_DropClient( cl, NULL ); - return; - } + SV_DropClient( cl, NULL ); + return; + } Com_DPrintf( "ANTICHEAT: %s for %s\n", __func__, cl->name ); // SV_Begin_f will handle possible map change sv_client = cl; sv_player = cl->edict; - SV_Begin_f(); + SV_Begin_f(); sv_client = NULL; sv_player = NULL; } @@ -821,13 +821,13 @@ static void AC_ParseQueryReply( void ) { // udp message and thus showing "%s lost connection" right before the // player leaves the server static void AC_ParseDisconnect ( void ) { - client_t *cl; + client_t *cl; cl = AC_ParseClient(); if( cl ) { - Com_Printf( "ANTICHEAT: Dropping %s, disconnect message.\n", cl->name ); - SV_DropClient( cl, NULL ); - } + Com_Printf( "ANTICHEAT: Dropping %s, disconnect message.\n", cl->name ); + SV_DropClient( cl, NULL ); + } } static void AC_ParseError( void ) { @@ -867,7 +867,7 @@ static qboolean AC_ParseMessage( void ) { ac.msglen = 0; cmd = MSG_ReadByte(); - switch( cmd ) { + switch( cmd ) { case ACS_VIOLATION: AC_ParseViolation(); break; @@ -911,7 +911,7 @@ static qboolean AC_ParseMessage( void ) { "Anticheat disabled.\n", cmd ); AC_Disable(); return qfalse; - } + } if( msg_read.readcount > msg_read.cursize ) { Com_WPrintf( "ANTICHEAT: Read %d bytes past end of message %d\n", @@ -941,24 +941,28 @@ static void AC_Write( const char *func ) { } static void AC_ClientQuery( client_t *cl ) { - cl->ac_query_sent = AC_QUERY_SENT; - cl->ac_query_time = svs.realtime; + cl->ac_query_sent = AC_QUERY_SENT; + cl->ac_query_time = svs.realtime; - if( !ac.ready ) - return; + if( !ac.ready ) + return; - //if( ac_nag_time->integer ) - // cl->anticheat_nag_time = svs.realtime; + //if( ac_nag_time->integer ) + // cl->anticheat_nag_time = svs.realtime; MSG_WriteShort( 9 ); - MSG_WriteByte( ACC_QUERYCLIENT ); - MSG_WriteLong( cl->number ); + MSG_WriteByte( ACC_QUERYCLIENT ); + MSG_WriteLong( cl->number ); MSG_WriteLong( cl->challenge ); AC_Write( __func__ ); } qboolean AC_ClientBegin( client_t *cl ) { - if( cl->ac_required == AC_EXEMPT ) { + if( !ac_required->integer ) { + return qtrue; // anticheat is not in use + } + + if( cl->ac_required == AC_EXEMPT ) { return qtrue; // client is EXEMPT } @@ -971,7 +975,7 @@ qboolean AC_ClientBegin( client_t *cl ) { return qfalse; // not yet QUERIED } - if( cl->ac_required != AC_REQUIRED ) { + if( cl->ac_required != AC_REQUIRED ) { return qtrue; // anticheat is NOT REQUIRED } @@ -1003,10 +1007,10 @@ qboolean AC_ClientBegin( client_t *cl ) { } void AC_ClientAnnounce( client_t *cl ) { - if( !ac_required->integer ) { - return; + if( !ac_required->integer ) { + return; // anticheat is not in use } - if( cl->state <= cs_zombie ) { + if( cl->state <= cs_zombie ) { return; } if( cl->ac_required == AC_EXEMPT ) { @@ -1027,7 +1031,7 @@ void AC_ClientAnnounce( client_t *cl ) { char *AC_ClientConnect( client_t *cl ) { if( !ac_required->integer ) { - return ""; + return ""; // anticheat is not in use } if( SV_MatchAddress( &ac_exempt_list, &net_from ) ) { @@ -1059,15 +1063,15 @@ char *AC_ClientConnect( client_t *cl ) { } void AC_ClientDisconnect( client_t *cl ) { - cl->ac_query_sent = AC_QUERY_UNSENT; - cl->ac_valid = qfalse; + cl->ac_query_sent = AC_QUERY_UNSENT; + cl->ac_valid = qfalse; - if( !ac.ready ) - return; + if( !ac.ready ) + return; MSG_WriteShort( 9 ); - MSG_WriteByte( ACC_CLIENTDISCONNECT ); - MSG_WriteLong( cl->number ); + MSG_WriteByte( ACC_CLIENTDISCONNECT ); + MSG_WriteLong( cl->number ); MSG_WriteLong( cl->challenge ); AC_Write( __func__ ); } @@ -1076,6 +1080,10 @@ void AC_ClientToken( client_t *cl, const char *token ) { string_entry_t *tok; client_t *other; + if( !ac_required->integer ) { + return; // anticheat is not in use + } + for( tok = acs.tokens; tok; tok = tok->next ) { if( !strcmp( tok->string, token ) ) { break; @@ -1088,12 +1096,13 @@ void AC_ClientToken( client_t *cl, const char *token ) { FOR_EACH_CLIENT( other ) { // FIXME: after `svacupdate' this check is incorrect - if( other->ac_token == token ) { + if( other->ac_token == tok->string ) { SV_DropClient( other, "duplicate anticheat token" ); } } - Com_Printf( "ANTICHEAT: %s bypassed anticheat requirements with token '%s'\n", + Com_Printf( + "ANTICHEAT: %s bypassed anticheat requirements with token '%s'\n", cl->name, tok->string ); cl->ac_token = tok->string; cl->ac_required = AC_EXEMPT; @@ -1233,7 +1242,7 @@ static void AC_CheckTimeouts( void ) { if( ac.ping_pending ) { if( svs.realtime - ac.last_ping > AC_PING_TIMEOUT ) { - Com_Printf( "ANTICHEAT: Server ping timeout, disconnecting.\n" ); + Com_Printf( "ANTICHEAT: Server ping timeout, disconnecting.\n" ); AC_Drop(); return; } @@ -1244,7 +1253,7 @@ static void AC_CheckTimeouts( void ) { } FOR_EACH_CLIENT( cl ) { - if( cl->state < cs_connected || cl->state > cs_primed ) { + if( cl->state < cs_connected || cl->state > cs_primed ) { continue; } if( cl->ac_query_sent != AC_QUERY_SENT ) { @@ -1258,7 +1267,7 @@ static void AC_CheckTimeouts( void ) { SV_Begin_f(); sv_client = NULL; sv_player = NULL; - } + } } } @@ -1301,7 +1310,7 @@ void AC_Run( void ) { if( acs.retry_time ) { clock = time( NULL ); if( acs.retry_time < clock ) { - Com_Printf( "ANTICHEAT: Attempting to reconnect to anticheat server...\n" ); + Com_Printf( "ANTICHEAT: Attempting to reconnect to anticheat server...\n" ); AC_Reconnect(); } return; @@ -1350,20 +1359,20 @@ void AC_Connect( qboolean ismvd ) { #if USE_CLIENT if( !dedicated->integer ) { - Com_Printf( "ANTICHEAT: Only supported on dedicated servers, disabling.\n" ); + Com_Printf( "ANTICHEAT: Only supported on dedicated servers, disabling.\n" ); Cvar_SetByVar( ac_required, "0", CVAR_SET_DIRECT ); return; } #endif if( ismvd ) { - Com_Printf( "ANTICHEAT: Only supported on game servers, disabling.\n" ); + Com_Printf( "ANTICHEAT: Only supported on game servers, disabling.\n" ); Cvar_SetByVar( ac_required, "0", CVAR_SET_DIRECT ); return; } AC_LoadChecks(); - Com_Printf( "ANTICHEAT: Attempting to connect to %s...\n", ac_server_address->string ); + Com_Printf( "ANTICHEAT: Attempting to connect to %s...\n", ac_server_address->string ); Sys_RunConsole(); acs.retry_backoff = AC_DEFAULT_BACKOFF; @@ -1381,7 +1390,7 @@ void AC_Connect( qboolean ismvd ) { } } - Com_WPrintf( "ANTICHEAT: Still not ready, resuming server initialization.\n" ); + Com_WPrintf( "ANTICHEAT: Still not ready, resuming server initialization.\n" ); } void AC_Disconnect( void ) { @@ -1395,34 +1404,34 @@ void AC_Disconnect( void ) { } void AC_List_f( void ) { - client_t *cl; - char *sub; - int i; + client_t *cl; + char *sub; + int i; if( !svs.initialized ) { - Com_Printf( "No server running.\n" ); + Com_Printf( "No server running.\n" ); return; } - if( !ac_required->integer ) { - Com_Printf( "The anticheat module is not in use on this server.\n" + if( !ac_required->integer ) { + Com_Printf( "The anticheat module is not in use on this server.\n" "For information on anticheat, please visit http://antiche.at/\n" ); - return; - } + return; + } - sub = Cmd_Argv( 1 ); + sub = Cmd_Argv( 1 ); - Com_Printf( - "+----------------+--------+-----+------+\n" - "| Player Name |AC Valid|Files|Client|\n" - "+----------------+--------+-----+------+\n" ); + Com_Printf( + "+----------------+--------+-----+------+\n" + "| Player Name |AC Valid|Files|Client|\n" + "+----------------+--------+-----+------+\n" ); FOR_EACH_CLIENT( cl ) { - if( cl->state < cs_spawned ) { - continue; + if( cl->state < cs_spawned ) { + continue; } - if( *sub && !strstr( cl->name, sub ) ) { + if( *sub && !strstr( cl->name, sub ) ) { continue; } @@ -1438,9 +1447,9 @@ void AC_List_f( void ) { } else { Com_Printf( "|%-16s| NO | N/A | N/A |\n", cl->name ); } - } + } - Com_Printf( "+----------------+--------+-----+------+\n" ); + Com_Printf( "+----------------+--------+-----+------+\n" ); if( ac.ready ) { Com_Printf( "File check list in use: %s\n", acs.hashlist_name ); @@ -1453,115 +1462,122 @@ void AC_List_f( void ) { } void AC_Info_f( void ) { - client_t *cl; - string_entry_t *bad; - char *substring, *filesubstring; - int clientID; + client_t *cl; + string_entry_t *bad; + char *substring, *filesubstring; + int clientID; if( !svs.initialized ) { - Com_Printf( "No server running.\n" ); + Com_Printf( "No server running.\n" ); return; } - if( !ac_required->integer ) { - Com_Printf( "The anticheat module is not in use on this server.\n" + if( !ac_required->integer ) { + Com_Printf( "The anticheat module is not in use on this server.\n" "For information on anticheat, please visit http://antiche.at/\n" ); - return; - } + return; + } - if( Cmd_Argc() == 1 ) { + if( Cmd_Argc() == 1 ) { if( !sv_client ) { - Com_Printf( "Usage: %s [substring|id] [filesubstring]\n", Cmd_Argv( 0 ) ); + Com_Printf( "Usage: %s [substring|id] [filesubstring]\n", Cmd_Argv( 0 ) ); return; } - cl = sv_client; - filesubstring = ""; - } else { - substring = Cmd_Argv( 1 ); - filesubstring = Cmd_Argv( 2 ); - - if( COM_IsUint( substring ) ) { - clientID = atoi( substring ); - if( clientID < 0 || clientID >= sv_maxclients->integer ) { - Com_Printf( "Invalid client ID.\n" ); - return; - } + cl = sv_client; + filesubstring = ""; + } else { + substring = Cmd_Argv( 1 ); + filesubstring = Cmd_Argv( 2 ); + + if( COM_IsUint( substring ) ) { + clientID = atoi( substring ); + if( clientID < 0 || clientID >= sv_maxclients->integer ) { + Com_Printf( "Invalid client ID.\n" ); + return; + } cl = &svs.udp_client_pool[clientID]; if( cl->state < cs_spawned ) { Com_Printf( "Player is not active.\n" ); return; } - } else { + } else { FOR_EACH_CLIENT( cl ) { - if( cl->state < cs_spawned ) { - continue; + if( cl->state < cs_spawned ) { + continue; + } + if( strstr( cl->name, substring ) ) { + goto found; } - if( strstr( cl->name, substring ) ) { - goto found; - } - } + } Com_Printf( "Player not found.\n" ); return; - } - } + } + } found: - if( !cl->ac_valid ) { - Com_Printf( "%s is not using anticheat.\n", cl->name ); - return; - } + if( !cl->ac_valid ) { + Com_Printf( "%s is not using anticheat.\n", cl->name ); + return; + } if( cl->ac_bad_files ) { - Com_Printf( "File check failures for %s:\n", cl->name ); + Com_Printf( "File check failures for %s:\n", cl->name ); for( bad = cl->ac_bad_files; bad; bad = bad->next ) { if( !filesubstring[0] || strstr( bad->string, filesubstring ) ) { - Com_Printf( "%s\n", bad->string ); + Com_Printf( "%s\n", bad->string ); } } } else { - Com_Printf( "%s has no file check failures.\n", cl->name ); + Com_Printf( "%s has no file check failures.\n", cl->name ); } } static void AC_Invalidate_f( void ) { - client_t *cl; + client_t *cl; if( !svs.initialized ) { - Com_Printf( "No server running.\n" ); + Com_Printf( "No server running.\n" ); + return; + } + if( !ac.ready ) { + Com_Printf( "Anticheat is not ready.\n" ); return; } - if( !ac.ready ) { - Com_Printf( "Anticheat is not ready.\n" ); - return; - } FOR_EACH_CLIENT( cl ) { - if( cl->state > cs_connected ) { - AC_ClientDisconnect( cl ); + if( cl->state > cs_connected ) { + AC_ClientDisconnect( cl ); } - } + } - Com_Printf( "All clients marked as invalid.\n" ); + Com_Printf( "All clients marked as invalid.\n" ); } static void AC_Update_f( void ) { + client_t *cl; + if( !svs.initialized ) { - Com_Printf( "No server running.\n" ); + Com_Printf( "No server running.\n" ); return; } if( !ac_required->integer ) { - Com_Printf( "Anticheat is not in use.\n" ); - return; + Com_Printf( "Anticheat is not in use.\n" ); + return; } AC_FreeChecks(); AC_LoadChecks(); - if( ac.connected ) { - AC_SendChecks(); - } + if( ac.connected ) { + AC_SendChecks(); + } + + // reset all tokens + FOR_EACH_CLIENT( cl ) { + cl->ac_token = NULL; + } - Com_Printf( "Anticheat configuration updated.\n" ); + Com_Printf( "Anticheat configuration updated.\n" ); } static void AC_AddException_f( void ) { diff --git a/source/sv_mvd.c b/source/sv_mvd.c index 6a106d0..35f88c5 100644 --- a/source/sv_mvd.c +++ b/source/sv_mvd.c @@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // #include "sv_local.h" -#include "gtv.h" +#include "mvd_gtv.h" #define FOR_EACH_GTV( client ) \ LIST_FOR_EACH( gtv_client_t, client, >v_client_list, entry ) @@ -570,9 +570,10 @@ static void emit_gamestate( void ) { int flags, extra, portalbytes; byte portalbits[MAX_MAP_AREAS/8]; + // pack MVD stream flags into extra bits extra = 0; if( sv_mvd_nomsgs->integer ) { - extra |= 1 << SVCMD_BITS; + extra |= MVF_NOMSGS << SVCMD_BITS; } // send the serverdata @@ -938,10 +939,10 @@ void SV_MvdEndFrame( void ) { // write frame to demofile if( mvd.recording ) { - uint16_t len; + uint16_t msglen; - len = LittleShort( total - 1 ); - FS_Write( &len, 2, mvd.recording ); + msglen = LittleShort( total - 1 ); + FS_Write( &msglen, 2, mvd.recording ); FS_Write( mvd.message.data, mvd.message.cursize, mvd.recording ); FS_Write( msg_write.data, msg_write.cursize, mvd.recording ); FS_Write( mvd.datagram.data, mvd.datagram.cursize, mvd.recording ); @@ -1387,6 +1388,7 @@ static void parse_ping( gtv_client_t *client ) { // send ping reply write_message( client, GTS_PONG ); + #if USE_ZLIB flush_stream( client, Z_SYNC_FLUSH ); #endif diff --git a/source/sv_world.c b/source/sv_world.c index 3ad9748..2d35b94 100644 --- a/source/sv_world.c +++ b/source/sv_world.c @@ -125,7 +125,7 @@ void SV_ClearWorld( void ) { =============== SV_LinkEdict -General purpose routine shared by game DLL and MVD code. +General purpose routine shared between game DLL and MVD code. Links entity to PVS leafs. =============== */ @@ -435,14 +435,15 @@ static mnode_t *SV_HullForEntity( edict_t *ent ) { mmodel_t *model; if( ent->solid == SOLID_BSP ) { + int index = ent->s.modelindex - 1; + // explicit hulls in the BSP model - if( ent->s.modelindex < 2 || ent->s.modelindex > sv.cm.cache->nummodels ) { - Com_Error( ERR_DROP, "%s: inline model index %d out of range", - __func__, ent->s.modelindex ); + if( index <= 0 || index >= sv.cm.cache->nummodels ) { + Com_Error( ERR_DROP, "%s: inline model %d out of range", + __func__, index ); } - model = &sv.cm.cache->models[ ent->s.modelindex - 1 ]; - + model = &sv.cm.cache->models[index]; return model->headnode; } @@ -479,7 +480,8 @@ int SV_PointContents (vec3_t p) // might intersect, so do an exact clip headnode = SV_HullForEntity (hit); - c2 = CM_TransformedPointContents (p, headnode, hit->s.origin, hit->s.angles); + c2 = CM_TransformedPointContents (p, headnode, + hit->s.origin, hit->s.angles); contents |= c2; } |