summaryrefslogtreecommitdiff
path: root/src/qcommon
diff options
context:
space:
mode:
Diffstat (limited to 'src/qcommon')
-rw-r--r--src/qcommon/cmd.c77
-rw-r--r--src/qcommon/common.c266
-rw-r--r--src/qcommon/cvar.c53
-rw-r--r--src/qcommon/files.c298
-rw-r--r--src/qcommon/msg.c8
-rw-r--r--src/qcommon/net_ip.c107
-rw-r--r--src/qcommon/q_platform.h7
-rw-r--r--src/qcommon/q_shared.c63
-rw-r--r--src/qcommon/q_shared.h35
-rw-r--r--src/qcommon/qcommon.h45
-rw-r--r--src/qcommon/unzip.c21
-rw-r--r--src/qcommon/vm.c14
-rw-r--r--src/qcommon/vm_local.h2
-rw-r--r--src/qcommon/vm_powerpc.c6
-rw-r--r--src/qcommon/vm_powerpc_asm.c7
-rw-r--r--src/qcommon/vm_sparc.c6
-rw-r--r--src/qcommon/vm_x86.c33
-rw-r--r--src/qcommon/vm_x86_64.c32
-rw-r--r--src/qcommon/vm_x86_64_assembler.c29
19 files changed, 683 insertions, 426 deletions
diff --git a/src/qcommon/cmd.c b/src/qcommon/cmd.c
index 7ce50ccc..8ea761e8 100644
--- a/src/qcommon/cmd.c
+++ b/src/qcommon/cmd.c
@@ -470,6 +470,31 @@ char *Cmd_Cmd(void)
}
/*
+ Replace command separators with space to prevent interpretation
+ This is a hack to protect buggy qvms
+ https://bugzilla.icculus.org/show_bug.cgi?id=3593
+ https://bugzilla.icculus.org/show_bug.cgi?id=4769
+*/
+
+void Cmd_Args_Sanitize(void)
+{
+ int i;
+
+ for(i = 1; i < cmd.argc; i++)
+ {
+ char *c = cmd.argv[i];
+
+ if(strlen(c) > MAX_CVAR_VALUE_STRING - 1)
+ c[MAX_CVAR_VALUE_STRING - 1] = '\0';
+
+ while ((c = strpbrk(c, "\n\r;"))) {
+ *c = ' ';
+ ++c;
+ }
+ }
+}
+
+/*
============
Cmd_TokenizeString
@@ -604,6 +629,20 @@ void Cmd_TokenizeStringIgnoreQuotes( const char *text_in ) {
/*
============
+Cmd_FindCommand
+============
+*/
+cmd_function_t *Cmd_FindCommand( const char *cmd_name )
+{
+ cmd_function_t *cmd;
+ for( cmd = cmd_functions; cmd; cmd = cmd->next )
+ if( !Q_stricmp( cmd_name, cmd->name ) )
+ return cmd;
+ return NULL;
+}
+
+/*
+============
Cmd_AddCommand
============
*/
@@ -611,14 +650,12 @@ void Cmd_AddCommand( const char *cmd_name, xcommand_t function ) {
cmd_function_t *cmd;
// fail if the command already exists
- for ( cmd = cmd_functions ; cmd ; cmd=cmd->next ) {
- if ( !strcmp( cmd_name, cmd->name ) ) {
- // allow completion-only commands to be silently doubled
- if ( function != NULL ) {
- Com_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
- }
- return;
- }
+ if( Cmd_FindCommand( cmd_name ) )
+ {
+ // allow completion-only commands to be silently doubled
+ if( function != NULL )
+ Com_Printf( "Cmd_AddCommand: %s already defined\n", cmd_name );
+ return;
}
// use a small malloc to avoid zone fragmentation
@@ -672,6 +709,28 @@ void Cmd_RemoveCommand( const char *cmd_name ) {
}
}
+/*
+============
+Cmd_RemoveCommandSafe
+
+Only remove commands with no associated function
+============
+*/
+void Cmd_RemoveCommandSafe( const char *cmd_name )
+{
+ cmd_function_t *cmd = Cmd_FindCommand( cmd_name );
+
+ if( !cmd )
+ return;
+ if( cmd->function )
+ {
+ Com_Error( ERR_DROP, "Restricted source tried to remove "
+ "system command \"%s\"\n", cmd_name );
+ return;
+ }
+
+ Cmd_RemoveCommand( cmd_name );
+}
/*
============
@@ -798,7 +857,7 @@ Cmd_CompleteCfgName
*/
void Cmd_CompleteCfgName( char *args, int argNum ) {
if( argNum == 2 ) {
- Field_CompleteFilename( "", "cfg", qfalse );
+ Field_CompleteFilename( "", "cfg", qfalse, qtrue );
}
}
diff --git a/src/qcommon/common.c b/src/qcommon/common.c
index 38902e92..1cf54d07 100644
--- a/src/qcommon/common.c
+++ b/src/qcommon/common.c
@@ -51,6 +51,7 @@ jmp_buf abortframe; // an ERR_DROP occured, exit the entire frame
FILE *debuglogfile;
+static fileHandle_t pipefile;
static fileHandle_t logfile;
fileHandle_t com_journalFile; // events are written here
fileHandle_t com_journalDataFile; // config files are written here
@@ -60,7 +61,6 @@ cvar_t *com_developer;
cvar_t *com_dedicated;
cvar_t *com_timescale;
cvar_t *com_fixedtime;
-cvar_t *com_dropsim; // 0.0 to 1.0, simulated packet drops
cvar_t *com_journal;
cvar_t *com_maxfps;
cvar_t *com_altivec;
@@ -68,6 +68,7 @@ cvar_t *com_timedemo;
cvar_t *com_sv_running;
cvar_t *com_cl_running;
cvar_t *com_logfile; // 1 = buffer log, 2 = flush after each print
+cvar_t *com_pipefile;
cvar_t *com_showtrace;
cvar_t *com_version;
cvar_t *com_blood;
@@ -83,6 +84,8 @@ cvar_t *com_maxfpsUnfocused;
cvar_t *com_minimized;
cvar_t *com_maxfpsMinimized;
cvar_t *com_abnormalExit;
+cvar_t *com_homepath;
+cvar_t *com_busyWait;
// com_speeds times
int time_game;
@@ -90,7 +93,6 @@ int time_frontend; // renderer frontend time
int time_backend; // renderer backend time
int com_frameTime;
-int com_frameMsec;
int com_frameNumber;
qboolean com_errorEntered = qfalse;
@@ -289,9 +291,9 @@ void QDECL Com_Error( int code, const char *fmt, ... ) {
Cvar_Set("com_errorMessage", com_errorMessage);
if (code == ERR_DISCONNECT || code == ERR_SERVERDISCONNECT) {
+ VM_Forced_Unload_Start();
SV_Shutdown( "Server disconnected" );
CL_Disconnect( qtrue );
- VM_Forced_Unload_Start();
CL_FlushMemory( );
VM_Forced_Unload_Done();
// make sure we can get at our local stuff
@@ -300,32 +302,36 @@ void QDECL Com_Error( int code, const char *fmt, ... ) {
longjmp (abortframe, -1);
} else if (code == ERR_DROP) {
Com_Printf ("********************\nERROR: %s\n********************\n", com_errorMessage);
+ VM_Forced_Unload_Start();
SV_Shutdown (va("Server crashed: %s", com_errorMessage));
CL_Disconnect( qtrue );
- VM_Forced_Unload_Start();
CL_FlushMemory( );
VM_Forced_Unload_Done();
FS_PureServerSetLoadedPaks("", "");
com_errorEntered = qfalse;
longjmp (abortframe, -1);
} else if ( code == ERR_NEED_CD ) {
+ VM_Forced_Unload_Start();
SV_Shutdown( "Server didn't have CD" );
if ( com_cl_running && com_cl_running->integer ) {
CL_Disconnect( qtrue );
- VM_Forced_Unload_Start();
CL_FlushMemory( );
VM_Forced_Unload_Done();
CL_CDDialog();
} else {
Com_Printf("Server didn't have CD\n" );
+ VM_Forced_Unload_Done();
}
+
FS_PureServerSetLoadedPaks("", "");
com_errorEntered = qfalse;
longjmp (abortframe, -1);
} else {
+ VM_Forced_Unload_Start();
CL_Shutdown (va("Client fatal crashed: %s", com_errorMessage));
SV_Shutdown (va("Server fatal crashed: %s", com_errorMessage));
+ VM_Forced_Unload_Done();
}
Com_Shutdown ();
@@ -446,7 +452,6 @@ be after execing the config and default.
void Com_StartupVariable( const char *match ) {
int i;
char *s;
- cvar_t *cv;
for (i=0 ; i < com_numConsoleLines ; i++) {
Cmd_TokenizeString( com_consoleLines[i] );
@@ -455,11 +460,13 @@ void Com_StartupVariable( const char *match ) {
}
s = Cmd_Argv(1);
- if ( !match || !strcmp( s, match ) ) {
- Cvar_Set( s, Cmd_Argv(2) );
- cv = Cvar_Get( s, "", 0 );
- cv->flags |= CVAR_USER_CREATED;
-// com_consoleLines[i] = 0;
+
+ if(!match || !strcmp(s, match))
+ {
+ if(Cvar_Flags(s) == CVAR_NONEXISTENT)
+ Cvar_Get(s, Cmd_Argv(2), CVAR_USER_CREATED);
+ else
+ Cvar_Set(s, Cmd_Argv(2));
}
}
}
@@ -504,8 +511,8 @@ qboolean Com_AddStartupCommands( void ) {
//============================================================================
void Info_Print( const char *s ) {
- char key[512];
- char value[512];
+ char key[BIG_INFO_KEY];
+ char value[BIG_INFO_VALUE];
char *o;
int l;
@@ -525,7 +532,7 @@ void Info_Print( const char *s ) {
}
else
*o = 0;
- Com_Printf ("%s", key);
+ Com_Printf ("%s ", key);
if (!*s)
{
@@ -1946,7 +1953,6 @@ EVENT LOOP
static sysEvent_t eventQueue[ MAX_QUEUED_EVENTS ];
static int eventHead = 0;
static int eventTail = 0;
-static byte sys_packetReceived[ MAX_MSGLEN ];
/*
================
@@ -1999,8 +2005,6 @@ sysEvent_t Com_GetSystemEvent( void )
{
sysEvent_t ev;
char *s;
- msg_t netmsg;
- netadr_t adr;
// return if we have data
if ( eventHead > eventTail )
@@ -2022,21 +2026,6 @@ sysEvent_t Com_GetSystemEvent( void )
Com_QueueEvent( 0, SE_CONSOLE, 0, 0, len, b );
}
- // check for network packets
- MSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) );
- if ( Sys_GetPacket ( &adr, &netmsg ) )
- {
- netadr_t *buf;
- int len;
-
- // copy out to a seperate buffer for qeueing
- len = sizeof( netadr_t ) + netmsg.cursize;
- buf = Z_Malloc( len );
- *buf = adr;
- memcpy( buf+1, netmsg.data, netmsg.cursize );
- Com_QueueEvent( 0, SE_PACKET, 0, 0, len, buf );
- }
-
// return if we have data
if ( eventHead > eventTail )
{
@@ -2196,7 +2185,6 @@ int Com_EventLoop( void ) {
MSG_Init( &buf, bufData, sizeof( bufData ) );
while ( 1 ) {
- NET_FlushPacketQueue();
ev = Com_GetEvent();
// if no more events are available
@@ -2217,57 +2205,26 @@ int Com_EventLoop( void ) {
}
- switch ( ev.evType ) {
- default:
- Com_Error( ERR_FATAL, "Com_EventLoop: bad event type %i", ev.evType );
- break;
- case SE_NONE:
- break;
- case SE_KEY:
- CL_KeyEvent( ev.evValue, ev.evValue2, ev.evTime );
+ switch(ev.evType)
+ {
+ case SE_KEY:
+ CL_KeyEvent( ev.evValue, ev.evValue2, ev.evTime );
break;
- case SE_CHAR:
- CL_CharEvent( ev.evValue );
+ case SE_CHAR:
+ CL_CharEvent( ev.evValue );
break;
- case SE_MOUSE:
- CL_MouseEvent( ev.evValue, ev.evValue2, ev.evTime );
+ case SE_MOUSE:
+ CL_MouseEvent( ev.evValue, ev.evValue2, ev.evTime );
break;
- case SE_JOYSTICK_AXIS:
- CL_JoystickEvent( ev.evValue, ev.evValue2, ev.evTime );
+ case SE_JOYSTICK_AXIS:
+ CL_JoystickEvent( ev.evValue, ev.evValue2, ev.evTime );
break;
- case SE_CONSOLE:
- Cbuf_AddText( (char *)ev.evPtr );
- Cbuf_AddText( "\n" );
+ case SE_CONSOLE:
+ Cbuf_AddText( (char *)ev.evPtr );
+ Cbuf_AddText( "\n" );
break;
- case SE_PACKET:
- // this cvar allows simulation of connections that
- // drop a lot of packets. Note that loopback connections
- // don't go through here at all.
- if ( com_dropsim->value > 0 ) {
- static int seed;
-
- if ( Q_random( &seed ) < com_dropsim->value ) {
- break; // drop this packet
- }
- }
-
- evFrom = *(netadr_t *)ev.evPtr;
- buf.cursize = ev.evPtrLength - sizeof( evFrom );
-
- // we must copy the contents of the message out, because
- // the event buffers are only large enough to hold the
- // exact payload, but channel messages need to be large
- // enough to hold fragment reassembly
- if ( (unsigned)buf.cursize > buf.maxsize ) {
- Com_Printf("Com_EventLoop: oversize packet\n");
- continue;
- }
- Com_Memcpy( buf.data, (byte *)((netadr_t *)ev.evPtr + 1), buf.cursize );
- if ( com_sv_running->integer ) {
- Com_RunAndTimeServerPacket( &evFrom, &buf );
- } else {
- CL_PacketEvent( evFrom, &buf );
- }
+ default:
+ Com_Error( ERR_FATAL, "Com_EventLoop: bad event type %i", ev.evType );
break;
}
@@ -2518,7 +2475,6 @@ void Com_Init( char *commandLine ) {
// Clear queues
Com_Memset( &eventQueue[ 0 ], 0, MAX_QUEUED_EVENTS * sizeof( sysEvent_t ) );
- Com_Memset( &sys_packetReceived[ 0 ], 0, MAX_MSGLEN * sizeof( byte ) );
// initialize the weak pseudo-random number generator for use later.
Com_InitRand();
@@ -2543,11 +2499,14 @@ void Com_Init( char *commandLine ) {
Cmd_Init ();
// get the developer cvar set as early as possible
- Com_StartupVariable( "developer" );
+ com_developer = Cvar_Get("developer", "0", CVAR_TEMP);
// done early so bind command exists
CL_InitKeyCommands();
+ com_homepath = Cvar_Get("com_homepath", "", CVAR_INIT);
+
+ // Com_StartupVariable(
FS_InitFilesystem ();
Com_InitJournaling();
@@ -2593,13 +2552,11 @@ void Com_Init( char *commandLine ) {
com_maxfps = Cvar_Get ("com_maxfps", "85", CVAR_ARCHIVE);
com_blood = Cvar_Get ("com_blood", "1", CVAR_ARCHIVE);
- com_developer = Cvar_Get ("developer", "0", CVAR_TEMP );
com_logfile = Cvar_Get ("logfile", "0", CVAR_TEMP );
com_timescale = Cvar_Get ("timescale", "1", CVAR_CHEAT | CVAR_SYSTEMINFO );
com_fixedtime = Cvar_Get ("fixedtime", "0", CVAR_CHEAT);
com_showtrace = Cvar_Get ("com_showtrace", "0", CVAR_CHEAT);
- com_dropsim = Cvar_Get ("com_dropsim", "0", CVAR_CHEAT);
com_speeds = Cvar_Get ("com_speeds", "0", 0);
com_timedemo = Cvar_Get ("timedemo", "0", CVAR_CHEAT);
com_cameraMode = Cvar_Get ("com_cameraMode", "0", CVAR_CHEAT);
@@ -2618,6 +2575,7 @@ void Com_Init( char *commandLine ) {
com_minimized = Cvar_Get( "com_minimized", "0", CVAR_ROM );
com_maxfpsMinimized = Cvar_Get( "com_maxfpsMinimized", "0", CVAR_ARCHIVE );
com_abnormalExit = Cvar_Get( "com_abnormalExit", "0", CVAR_ROM );
+ com_busyWait = Cvar_Get("com_busyWait", "0", CVAR_ARCHIVE);
s = va("%s %s %s", Q3_VERSION, PLATFORM_STRING, __DATE__ );
com_version = Cvar_Get ("version", s, CVAR_ROM | CVAR_SERVERINFO );
@@ -2677,9 +2635,36 @@ void Com_Init( char *commandLine ) {
Com_Printf ("Altivec support is %s\n", com_altivec->integer ? "enabled" : "disabled");
#endif
+ com_pipefile = Cvar_Get( "com_pipefile", "", CVAR_ARCHIVE|CVAR_LATCH );
+ if( com_pipefile->string[0] )
+ {
+ pipefile = FS_FCreateOpenPipeFile( com_pipefile->string );
+ }
+
Com_Printf ("--- Common Initialization Complete ---\n");
}
+/*
+===============
+Com_ReadFromPipe
+
+Read whatever is in com_pipefile, if anything, and execute it
+===============
+*/
+void Com_ReadFromPipe( void )
+{
+ char buffer[MAX_STRING_CHARS] = {""};
+ qboolean read;
+
+ if( !pipefile )
+ return;
+
+ read = FS_Read( buffer, sizeof( buffer ), pipefile );
+ if( read )
+ Cbuf_ExecuteText( EXEC_APPEND, buffer );
+}
+
+
//==================================================================
void Com_WriteConfigToFile( const char *filename ) {
@@ -2801,19 +2786,16 @@ Com_Frame
void Com_Frame( void ) {
int msec, minMsec;
- static int lastTime;
- int key;
+ int timeVal;
+ static int lastTime = 0, bias = 0;
int timeBeforeFirstEvents;
- int timeBeforeServer;
- int timeBeforeEvents;
- int timeBeforeClient;
- int timeAfter;
+ int timeBeforeServer;
+ int timeBeforeEvents;
+ int timeBeforeClient;
+ int timeAfter;
-
-
-
if ( setjmp (abortframe) ) {
return; // an ERR_DROP was thrown
}
@@ -2824,10 +2806,6 @@ void Com_Frame( void ) {
timeBeforeClient = 0;
timeAfter = 0;
-
- // old net chan encryption key
- key = 0x87243987;
-
// write config file if anything changed
Com_WriteConfiguration();
@@ -2838,37 +2816,59 @@ void Com_Frame( void ) {
timeBeforeFirstEvents = Sys_Milliseconds ();
}
- // we may want to spin here if things are going too fast
- if ( !com_dedicated->integer && !com_timedemo->integer ) {
- if( com_minimized->integer && com_maxfpsMinimized->integer > 0 ) {
- minMsec = 1000 / com_maxfpsMinimized->integer;
- } else if( com_unfocused->integer && com_maxfpsUnfocused->integer > 0 ) {
- minMsec = 1000 / com_maxfpsUnfocused->integer;
- } else if( com_maxfps->integer > 0 ) {
- minMsec = 1000 / com_maxfps->integer;
- } else {
- minMsec = 1;
+ // Figure out how much time we have
+ if(!com_timedemo->integer)
+ {
+ if(com_dedicated->integer)
+ minMsec = SV_FrameMsec();
+ else
+ {
+ if(com_minimized->integer && com_maxfpsMinimized->integer > 0)
+ minMsec = 1000 / com_maxfpsMinimized->integer;
+ else if(com_unfocused->integer && com_maxfpsUnfocused->integer > 0)
+ minMsec = 1000 / com_maxfpsUnfocused->integer;
+ else if(com_maxfps->integer > 0)
+ minMsec = 1000 / com_maxfps->integer;
+ else
+ minMsec = 1;
+
+ timeVal = com_frameTime - lastTime;
+ bias += timeVal - minMsec;
+
+ if(bias > minMsec)
+ bias = minMsec;
+
+ // Adjust minMsec if previous frame took too long to render so
+ // that framerate is stable at the requested value.
+ minMsec -= bias;
}
- } else {
- minMsec = 1;
}
+ else
+ minMsec = 1;
- msec = minMsec;
- do {
- int timeRemaining = minMsec - msec;
+ timeVal = 0;
+ do
+ {
+ // Busy sleep the last millisecond for better timeout precision
+ if(com_busyWait->integer || timeVal < 2)
+ NET_Sleep(0);
+ else
+ NET_Sleep(timeVal - 1);
- // The existing Sys_Sleep implementations aren't really
- // precise enough to be of use beyond 100fps
- // FIXME: implement a more precise sleep (RDTSC or something)
- if( timeRemaining >= 10 )
- Sys_Sleep( timeRemaining );
+ msec = Sys_Milliseconds() - com_frameTime;
+
+ if(msec >= minMsec)
+ timeVal = 0;
+ else
+ timeVal = minMsec - msec;
+
+ } while(timeVal > 0);
+
+ lastTime = com_frameTime;
+ com_frameTime = Com_EventLoop();
+
+ msec = com_frameTime - lastTime;
- com_frameTime = Com_EventLoop();
- if ( lastTime > com_frameTime ) {
- lastTime = com_frameTime; // possible on first frame
- }
- msec = com_frameTime - lastTime;
- } while ( msec < minMsec );
Cbuf_Execute ();
if (com_altivec->modified)
@@ -2877,11 +2877,8 @@ void Com_Frame( void ) {
com_altivec->modified = qfalse;
}
- lastTime = com_frameTime;
-
// mess with msec if needed
- com_frameMsec = msec;
- msec = Com_ModifyMsec( msec );
+ msec = Com_ModifyMsec(msec);
//
// server side
@@ -2941,6 +2938,9 @@ void Com_Frame( void ) {
}
#endif
+
+ NET_FlushPacketQueue();
+
//
// report timing information
//
@@ -2974,8 +2974,7 @@ void Com_Frame( void ) {
c_pointcontents = 0;
}
- // old net chan encryption key
- key = lastTime * 0x87243987;
+ Com_ReadFromPipe( );
com_frameNumber++;
}
@@ -2996,6 +2995,11 @@ void Com_Shutdown (void) {
com_journalFile = 0;
}
+ if( pipefile ) {
+ FS_FCloseFile( pipefile );
+ FS_HomeRemove( com_pipefile->string );
+ }
+
}
//------------------------------------------------------------------------
@@ -3183,15 +3187,15 @@ Field_CompleteFilename
===============
*/
void Field_CompleteFilename( const char *dir,
- const char *ext, qboolean stripExt )
+ const char *ext, qboolean stripExt, qboolean allowNonPureFilesOnDisk )
{
matchCount = 0;
shortestMatch[ 0 ] = 0;
- FS_FilenameCompletion( dir, ext, stripExt, FindMatches );
+ FS_FilenameCompletion( dir, ext, stripExt, FindMatches, allowNonPureFilesOnDisk );
if( !Field_Complete( ) )
- FS_FilenameCompletion( dir, ext, stripExt, PrintMatches );
+ FS_FilenameCompletion( dir, ext, stripExt, PrintMatches, allowNonPureFilesOnDisk );
}
/*
diff --git a/src/qcommon/cvar.c b/src/qcommon/cvar.c
index b0a21506..8db30e6a 100644
--- a/src/qcommon/cvar.c
+++ b/src/qcommon/cvar.c
@@ -364,6 +364,18 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) {
flags &= ~CVAR_VM_CREATED;
}
+ // Make sure servers cannot mark engine-added variables as SERVER_CREATED
+ if(var->flags & CVAR_SERVER_CREATED)
+ {
+ if(!(flags & CVAR_SERVER_CREATED))
+ var->flags &= ~CVAR_SERVER_CREATED;
+ }
+ else
+ {
+ if(flags & CVAR_SERVER_CREATED)
+ flags &= ~CVAR_SERVER_CREATED;
+ }
+
var->flags |= flags;
// only allow one non-empty reset string without a warning
@@ -613,6 +625,28 @@ void Cvar_Set( const char *var_name, const char *value) {
/*
============
+Cvar_SetSafe
+============
+*/
+void Cvar_SetSafe( const char *var_name, const char *value )
+{
+ int flags = Cvar_Flags( var_name );
+
+ if( flags != CVAR_NONEXISTENT && flags & CVAR_PROTECTED )
+ {
+ if( value )
+ Com_Error( ERR_DROP, "Restricted source tried to set "
+ "\"%s\" to \"%s\"\n", var_name, value );
+ else
+ Com_Error( ERR_DROP, "Restricted source tried to "
+ "modify \"%s\"\n", var_name );
+ return;
+ }
+ Cvar_Set( var_name, value );
+}
+
+/*
+============
Cvar_SetLatched
============
*/
@@ -636,6 +670,21 @@ void Cvar_SetValue( const char *var_name, float value) {
Cvar_Set (var_name, val);
}
+/*
+============
+Cvar_SetValueSafe
+============
+*/
+void Cvar_SetValueSafe( const char *var_name, float value )
+{
+ char val[32];
+
+ if( Q_isintegral( value ) )
+ Com_sprintf( val, sizeof(val), "%i", (int)value );
+ else
+ Com_sprintf( val, sizeof(val), "%f", value );
+ Cvar_SetSafe( var_name, val );
+}
/*
============
@@ -1211,9 +1260,9 @@ void Cvar_Update( vmCvar_t *vmCvar ) {
}
vmCvar->modificationCount = cv->modificationCount;
if ( strlen(cv->string)+1 > MAX_CVAR_VALUE_STRING )
- Com_Error( ERR_DROP, "Cvar_Update: src %s length %zd exceeds MAX_CVAR_VALUE_STRING",
+ Com_Error( ERR_DROP, "Cvar_Update: src %s length %u exceeds MAX_CVAR_VALUE_STRING",
cv->string,
- strlen(cv->string));
+ (unsigned int) strlen(cv->string));
Q_strncpyz( vmCvar->string, cv->string, MAX_CVAR_VALUE_STRING );
vmCvar->value = cv->value;
diff --git a/src/qcommon/files.c b/src/qcommon/files.c
index 302ce0fe..62617223 100644
--- a/src/qcommon/files.c
+++ b/src/qcommon/files.c
@@ -173,21 +173,6 @@ or configs will never get loaded from disk!
*/
-// every time a new demo pk3 file is built, this checksum must be updated.
-// the easiest way to get it is to just run the game and see what it spits out
-#define DEMO_PAK0_CHECKSUM 2985612116u
-static const unsigned pak_checksums[] = {
- 1566731103u,
- 298122907u,
- 412165236u,
- 2991495316u,
- 1197932710u,
- 4087071573u,
- 3709064859u,
- 908855077u,
- 977125798u
-};
-
// if this is defined, the executable positively won't work with any paks other
// than the demo pak, even if productid is present. This is only used for our
// last demo release to prevent the mac and linux users from using the demo
@@ -326,7 +311,7 @@ qboolean FS_PakIsPure( pack_t *pack ) {
for ( i = 0 ; i < fs_numServerPaks ; i++ ) {
// FIXME: also use hashed file names
// NOTE TTimo: a pk3 with same checksum but different name would be validated too
- // I don't see this as allowing for any exploit, it would only happen if the client does manips of it's file names 'not a bug'
+ // I don't see this as allowing for any exploit, it would only happen if the client does manips of its file names 'not a bug'
if ( pack->checksum == fs_serverPaks[i] ) {
return qtrue; // on the aproved list
}
@@ -538,57 +523,6 @@ static void FS_CheckFilenameIsNotExecutable( const char *filename,
}
}
-
-/*
-=================
-FS_CopyFile
-
-Copy a fully specified file from one place to another
-=================
-*/
-static void FS_CopyFile( char *fromOSPath, char *toOSPath ) {
- FILE *f;
- int len;
- byte *buf;
-
- Com_Printf( "copy %s to %s\n", fromOSPath, toOSPath );
-
- FS_CheckFilenameIsNotExecutable( toOSPath, __func__ );
-
- if (strstr(fromOSPath, "journal.dat") || strstr(fromOSPath, "journaldata.dat")) {
- Com_Printf( "Ignoring journal files\n");
- return;
- }
-
- f = fopen( fromOSPath, "rb" );
- if ( !f ) {
- return;
- }
- fseek (f, 0, SEEK_END);
- len = ftell (f);
- fseek (f, 0, SEEK_SET);
-
- // we are using direct malloc instead of Z_Malloc here, so it
- // probably won't work on a mac... Its only for developers anyway...
- buf = malloc( len );
- if (fread( buf, 1, len, f ) != len)
- Com_Error( ERR_FATAL, "Short read in FS_Copyfiles()\n" );
- fclose( f );
-
- if( FS_CreatePath( toOSPath ) ) {
- return;
- }
-
- f = fopen( toOSPath, "wb" );
- if ( !f ) {
- return;
- }
- if (fwrite( buf, 1, len, f ) != len)
- Com_Error( ERR_FATAL, "Short write in FS_Copyfiles()\n" );
- fclose( f );
- free( buf );
-}
-
/*
===========
FS_Remove
@@ -800,11 +734,7 @@ void FS_SV_Rename( const char *from, const char *to ) {
FS_CheckFilenameIsNotExecutable( to_ospath, __func__ );
- if (rename( from_ospath, to_ospath )) {
- // Failed, try copying it and deleting the original
- FS_CopyFile ( from_ospath, to_ospath );
- FS_Remove ( from_ospath );
- }
+ rename(from_ospath, to_ospath);
}
@@ -834,11 +764,7 @@ void FS_Rename( const char *from, const char *to ) {
FS_CheckFilenameIsNotExecutable( to_ospath, __func__ );
- if (rename( from_ospath, to_ospath )) {
- // Failed, try copying it and deleting the original
- FS_CopyFile ( from_ospath, to_ospath );
- FS_Remove ( from_ospath );
- }
+ rename(from_ospath, to_ospath);
}
/*
@@ -959,6 +885,52 @@ fileHandle_t FS_FOpenFileAppend( const char *filename ) {
/*
===========
+FS_FCreateOpenPipeFile
+
+===========
+*/
+fileHandle_t FS_FCreateOpenPipeFile( const char *filename ) {
+ char *ospath;
+ FILE *fifo;
+ fileHandle_t f;
+
+ if ( !fs_searchpaths ) {
+ Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
+ }
+
+ f = FS_HandleForFile();
+ fsh[f].zipFile = qfalse;
+
+ Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) );
+
+ // don't let sound stutter
+ S_ClearSoundBuffer();
+
+ ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, filename );
+
+ if ( fs_debug->integer ) {
+ Com_Printf( "FS_FCreateOpenPipeFile: %s\n", ospath );
+ }
+
+ FS_CheckFilenameIsNotExecutable( ospath, __func__ );
+
+ fifo = Sys_Mkfifo( ospath );
+ if( fifo ) {
+ fsh[f].handleFiles.file.o = fifo;
+ fsh[f].handleSync = qfalse;
+ }
+ else
+ {
+ Com_Printf( S_COLOR_YELLOW "WARNING: Could not create new com_pipefile at %s. "
+ "com_pipefile will not be used.\n", ospath );
+ f = 0;
+ }
+
+ return f;
+}
+
+/*
+===========
FS_FilenameCompare
Ignore case and seprator char distinctions
@@ -995,6 +967,59 @@ qboolean FS_FilenameCompare( const char *s1, const char *s2 ) {
/*
===========
+FS_IsExt
+
+Return qtrue if ext matches file extension filename
+===========
+*/
+
+qboolean FS_IsExt(const char *filename, const char *ext, int namelen)
+{
+ int extlen;
+
+ extlen = strlen(ext);
+
+ if(extlen > namelen)
+ return qfalse;
+
+ filename += namelen - extlen;
+
+ return !Q_stricmp(filename, ext);
+}
+
+/*
+===========
+FS_IsDemoExt
+
+Return qtrue if filename has a demo extension
+===========
+*/
+
+qboolean FS_IsDemoExt(const char *filename, int namelen)
+{
+ char *ext_test;
+ int index, protocol;
+
+ ext_test = Q_strrchr(filename, '.');
+ if(ext_test && !Q_stricmpn(ext_test + 1, DEMOEXT, ARRAY_LEN(DEMOEXT) - 1))
+ {
+ protocol = atoi(ext_test + ARRAY_LEN(DEMOEXT));
+
+ if(protocol == PROTOCOL_VERSION)
+ return qtrue;
+
+ for(index = 0; demo_protocols[index]; index++)
+ {
+ if(demo_protocols[index] == protocol)
+ return qtrue;
+ }
+ }
+
+ return qfalse;
+}
+
+/*
+===========
FS_FOpenFileRead
Finds the file in the search path.
@@ -1014,7 +1039,6 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF
long hash;
FILE *temp;
int l;
- char demoExt[16];
hash = 0;
@@ -1061,7 +1085,6 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF
Com_Error( ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed\n" );
}
- Com_sprintf (demoExt, sizeof(demoExt), ".dm_%d",PROTOCOL_VERSION );
// qpaths are not supposed to have a leading slash
if ( filename[0] == '/' || filename[0] == '\\' ) {
filename++;
@@ -1106,16 +1129,19 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF
// shaders, txt, arena files by themselves do not count as a reference as
// these are loaded from all pk3s
// from every pk3 file..
- l = strlen( filename );
- if ( !(pak->referenced & FS_GENERAL_REF)) {
- if ( Q_stricmp(filename + l - 7, ".shader") != 0 &&
- Q_stricmp(filename + l - 4, ".txt") != 0 &&
- Q_stricmp(filename + l - 4, ".cfg") != 0 &&
- Q_stricmp(filename + l - 7, ".config") != 0 &&
- strstr(filename, "levelshots") == NULL &&
- Q_stricmp(filename + l - 4, ".bot") != 0 &&
- Q_stricmp(filename + l - 6, ".arena") != 0 &&
- Q_stricmp(filename + l - 5, ".menu") != 0) {
+ l = strlen(filename);
+
+ if (!(pak->referenced & FS_GENERAL_REF))
+ {
+ if(!FS_IsExt(filename, ".shader", l) &&
+ !FS_IsExt(filename, ".txt", l) &&
+ !FS_IsExt(filename, ".cfg", l) &&
+ !FS_IsExt(filename, ".config", l) &&
+ !FS_IsExt(filename, ".bot", l) &&
+ !FS_IsExt(filename, ".arena", l) &&
+ !FS_IsExt(filename, ".menu", l) &&
+ !strstr(filename, "levelshots"))
+ {
pak->referenced |= FS_GENERAL_REF;
}
}
@@ -1166,13 +1192,14 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF
// this test can make the search fail although the file is in the directory
// I had the problem on https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8
// turned out I used FS_FileExists instead
- if ( fs_numServerPaks ) {
-
- if ( Q_stricmp( filename + l - 4, ".cfg" ) // for config files
- && Q_stricmp( filename + l - 5, ".menu" ) // menu files
- && Q_stricmp( filename + l - 5, ".game" ) // menu files
- && Q_stricmp( filename + l - strlen(demoExt), demoExt ) // menu files
- && Q_stricmp( filename + l - 4, ".dat" ) ) { // for journal files
+ if(fs_numServerPaks)
+ {
+ if(!FS_IsExt(filename, ".cfg", l) && // for config files
+ !FS_IsExt(filename, ".menu", l) && // menu files
+ !FS_IsExt(filename, ".game", l) && // menu files
+ !FS_IsExt(filename, ".cfg", l) && // for journal files
+ !FS_IsDemoExt(filename, l)) // demos
+ {
continue;
}
}
@@ -1206,6 +1233,32 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF
}
+char *FS_FindDll( const char *filename ) {
+ searchpath_t *search;
+ directory_t *dir;
+
+ if ( !fs_searchpaths ) {
+ Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
+ }
+
+ for ( search = fs_searchpaths ; search ; search = search->next ) {
+ if ( search->dir ) {
+ FILE *f;
+ char *netpath;
+
+ dir = search->dir;
+ netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
+ f = fopen( netpath, "rb" );
+ if (f) {
+ fclose( f );
+ return netpath;
+ }
+ }
+ }
+
+ return NULL;
+}
+
/*
=================
FS_Read
@@ -1881,7 +1934,7 @@ Returns a uniqued list of files that match the given criteria
from all search paths
===============
*/
-char **FS_ListFilteredFiles( const char *path, const char *extension, char *filter, int *numfiles ) {
+char **FS_ListFilteredFiles( const char *path, const char *extension, char *filter, int *numfiles, qboolean allowNonPureFilesOnDisk ) {
int nfiles;
char **listCopy;
char *list[MAX_FOUND_FILES];
@@ -1977,7 +2030,7 @@ char **FS_ListFilteredFiles( const char *path, const char *extension, char *filt
char *name;
// don't scan directories for files if we are pure or restricted
- if ( fs_numServerPaks ) {
+ if ( fs_numServerPaks && !allowNonPureFilesOnDisk ) {
continue;
} else {
netpath = FS_BuildOSPath( search->dir->path, search->dir->gamedir, path );
@@ -2014,7 +2067,7 @@ FS_ListFiles
=================
*/
char **FS_ListFiles( const char *path, const char *extension, int *numfiles ) {
- return FS_ListFilteredFiles( path, extension, NULL, numfiles );
+ return FS_ListFilteredFiles( path, extension, NULL, numfiles, qfalse );
}
/*
@@ -2393,7 +2446,7 @@ void FS_NewDir_f( void ) {
Com_Printf( "---------------\n" );
- dirnames = FS_ListFilteredFiles( "", "", filter, &ndirs );
+ dirnames = FS_ListFilteredFiles( "", "", filter, &ndirs, qfalse );
FS_SortFileList(dirnames, ndirs);
@@ -2605,25 +2658,6 @@ void FS_AddGameDirectory( const char *path, const char *dir ) {
/*
================
-FS_idPak
-================
-*/
-qboolean FS_idPak( char *pak, char *base ) {
- int i;
-
- for (i = 0; i < NUM_ID_PAKS; i++) {
- if ( !FS_FilenameCompare(pak, va("%s/pak%d", base, i)) ) {
- break;
- }
- }
- if (i < NUM_ID_PAKS) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-================
FS_CheckDirTraversal
Check whether the string contains stuff like "../" to prevent directory traversal bugs
@@ -2682,11 +2716,6 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
badchecksum = qfalse;
havepak = qfalse;
- // never autodownload any of the tremulous paks
- if ( FS_idPak(fs_serverReferencedPakNames[i], BASEGAME) ) {
- continue;
- }
-
// Make sure the server cannot make us write to non-quake3 directories.
if(FS_CheckDirTraversal(fs_serverReferencedPakNames[i]))
{
@@ -2863,13 +2892,13 @@ static void FS_Startup( const char *gameName )
fs_packFiles = 0;
fs_debug = Cvar_Get( "fs_debug", "0", 0 );
- fs_basepath = Cvar_Get ("fs_basepath", Sys_DefaultInstallPath(), CVAR_INIT );
+ fs_basepath = Cvar_Get ("fs_basepath", Sys_DefaultInstallPath(), CVAR_INIT|CVAR_PROTECTED );
fs_basegame = Cvar_Get ("fs_basegame", "", CVAR_INIT );
homePath = Sys_DefaultHomePath();
if (!homePath || !homePath[0]) {
homePath = fs_basepath->string;
}
- fs_homepath = Cvar_Get ("fs_homepath", homePath, CVAR_INIT );
+ fs_homepath = Cvar_Get ("fs_homepath", homePath, CVAR_INIT|CVAR_PROTECTED );
fs_gamedirvar = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
// add search path elements in reverse priority order
@@ -2879,7 +2908,7 @@ static void FS_Startup( const char *gameName )
// fs_homepath is somewhat particular to *nix systems, only add if relevant
#ifdef MACOS_X
- fs_apppath = Cvar_Get ("fs_apppath", Sys_DefaultAppPath(), CVAR_INIT );
+ fs_apppath = Cvar_Get ("fs_apppath", Sys_DefaultAppPath(), CVAR_INIT|CVAR_PROTECTED );
// Make MacOSX also include the base path included with the .app bundle
if (fs_apppath->string[0])
FS_AddGameDirectory(fs_apppath->string, gameName);
@@ -2937,7 +2966,6 @@ static void FS_Startup( const char *gameName )
Com_Printf( "%d files in pk3 files\n", fs_packFiles );
}
-
/*
=====================
FS_GamePureChecksum
@@ -3256,7 +3284,7 @@ void FS_PureServerSetReferencedPaks( const char *pakSums, const char *pakNames )
fs_serverReferencedPaks[i] = atoi( Cmd_Argv( i ) );
}
- for (i = 0 ; i < sizeof(fs_serverReferencedPakNames) / sizeof(*fs_serverReferencedPakNames); i++)
+ for (i = 0 ; i < ARRAY_LEN(fs_serverReferencedPakNames); i++)
{
if(fs_serverReferencedPakNames[i])
Z_Free(fs_serverReferencedPakNames[i]);
@@ -3465,13 +3493,13 @@ void FS_Flush( fileHandle_t f ) {
}
void FS_FilenameCompletion( const char *dir, const char *ext,
- qboolean stripExt, void(*callback)(const char *s) ) {
+ qboolean stripExt, void(*callback)(const char *s), qboolean allowNonPureFilesOnDisk ) {
char **filenames;
int nfiles;
int i;
char filename[ MAX_STRING_CHARS ];
- filenames = FS_ListFilteredFiles( dir, ext, NULL, &nfiles );
+ filenames = FS_ListFilteredFiles( dir, ext, NULL, &nfiles, allowNonPureFilesOnDisk );
FS_SortFileList( filenames, nfiles );
@@ -3487,3 +3515,11 @@ void FS_FilenameCompletion( const char *dir, const char *ext,
}
FS_FreeFileList( filenames );
}
+
+const char *FS_GetCurrentGameDir(void)
+{
+ if(fs_gamedirvar->string[0])
+ return fs_gamedirvar->string;
+
+ return BASEGAME;
+}
diff --git a/src/qcommon/msg.c b/src/qcommon/msg.c
index ba956bc8..05a7aa9f 100644
--- a/src/qcommon/msg.c
+++ b/src/qcommon/msg.c
@@ -885,7 +885,7 @@ void MSG_WriteDeltaEntity( msg_t *msg, struct entityState_s *from, struct entity
float fullFloat;
int *fromF, *toF;
- numFields = sizeof(entityStateFields)/sizeof(entityStateFields[0]);
+ numFields = ARRAY_LEN( entityStateFields );
// all fields should be 32 bits to avoid any compiler packing issues
// the "number" field is not part of the field list
@@ -1030,7 +1030,7 @@ void MSG_ReadDeltaEntity( msg_t *msg, entityState_t *from, entityState_t *to,
return;
}
- numFields = sizeof(entityStateFields)/sizeof(entityStateFields[0]);
+ numFields = ARRAY_LEN( entityStateFields );
lc = MSG_ReadByte(msg);
if ( lc > numFields || lc < 0 ) {
@@ -1203,7 +1203,7 @@ void MSG_WriteDeltaPlayerstate( msg_t *msg, struct playerState_s *from, struct p
c = msg->cursize;
- numFields = sizeof( playerStateFields ) / sizeof( playerStateFields[0] );
+ numFields = ARRAY_LEN( playerStateFields );
lc = 0;
for ( i = 0, field = playerStateFields ; i < numFields ; i++, field++ ) {
@@ -1353,7 +1353,7 @@ void MSG_ReadDeltaPlayerstate (msg_t *msg, playerState_t *from, playerState_t *t
print = 0;
}
- numFields = sizeof( playerStateFields ) / sizeof( playerStateFields[0] );
+ numFields = ARRAY_LEN( playerStateFields );
lc = MSG_ReadByte(msg);
if ( lc > numFields || lc < 0 ) {
diff --git a/src/qcommon/net_ip.c b/src/qcommon/net_ip.c
index c1e527c5..e3a95e4a 100644
--- a/src/qcommon/net_ip.c
+++ b/src/qcommon/net_ip.c
@@ -51,6 +51,7 @@ typedef unsigned short sa_family_t;
# define EADDRNOTAVAIL WSAEADDRNOTAVAIL
# define EAFNOSUPPORT WSAEAFNOSUPPORT
# define ECONNRESET WSAECONNRESET
+typedef u_long ioctlarg_t;
# define socketError WSAGetLastError( )
static WSADATA winsockdata;
@@ -86,6 +87,7 @@ typedef int SOCKET;
# define SOCKET_ERROR -1
# define closesocket close
# define ioctlsocket ioctl
+typedef int ioctlarg_t;
# define socketError errno
#endif
@@ -108,6 +110,8 @@ static cvar_t *net_port6;
static cvar_t *net_mcast6addr;
static cvar_t *net_mcast6iface;
+static cvar_t *net_dropsim;
+
static struct sockaddr socksRelayAddr;
static SOCKET ip_socket = INVALID_SOCKET;
@@ -202,7 +206,7 @@ char *NET_ErrorString( void ) {
default: return "NO ERROR";
}
#else
- return strerror (errno);
+ return strerror(socketError);
#endif
}
@@ -521,16 +525,17 @@ qboolean NET_IsLocalAddress( netadr_t adr ) {
/*
==================
-Sys_GetPacket
+NET_GetPacket
-Never called by the game logic, just the system event queing
+Receive one packet
==================
*/
#ifdef _DEBUG
int recvfromCount;
#endif
-qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) {
+qboolean NET_GetPacket(netadr_t *net_from, msg_t *net_message, fd_set *fdr)
+{
int ret;
struct sockaddr_storage from;
socklen_t fromlen;
@@ -540,7 +545,7 @@ qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) {
recvfromCount++; // performance check
#endif
- if(ip_socket != INVALID_SOCKET)
+ if(ip_socket != INVALID_SOCKET && FD_ISSET(ip_socket, fdr))
{
fromlen = sizeof(from);
ret = recvfrom( ip_socket, (void *)net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen );
@@ -574,7 +579,7 @@ qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) {
net_message->readcount = 0;
}
- if( ret == net_message->maxsize ) {
+ if( ret >= net_message->maxsize ) {
Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) );
return qfalse;
}
@@ -584,7 +589,7 @@ qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) {
}
}
- if(ip6_socket != INVALID_SOCKET)
+ if(ip6_socket != INVALID_SOCKET && FD_ISSET(ip6_socket, fdr))
{
fromlen = sizeof(from);
ret = recvfrom(ip6_socket, (void *)net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen);
@@ -601,7 +606,7 @@ qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) {
SockadrToNetadr((struct sockaddr *) &from, net_from);
net_message->readcount = 0;
- if(ret == net_message->maxsize)
+ if(ret >= net_message->maxsize)
{
Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) );
return qfalse;
@@ -612,7 +617,7 @@ qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) {
}
}
- if(multicast6_socket != INVALID_SOCKET && multicast6_socket != ip6_socket)
+ if(multicast6_socket != INVALID_SOCKET && multicast6_socket != ip6_socket && FD_ISSET(multicast6_socket, fdr))
{
fromlen = sizeof(from);
ret = recvfrom(multicast6_socket, (void *)net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen);
@@ -629,7 +634,7 @@ qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) {
SockadrToNetadr((struct sockaddr *) &from, net_from);
net_message->readcount = 0;
- if(ret == net_message->maxsize)
+ if(ret >= net_message->maxsize)
{
Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) );
return qfalse;
@@ -825,7 +830,7 @@ NET_IPSocket
int NET_IPSocket( char *net_interface, int port, int *err ) {
SOCKET newsocket;
struct sockaddr_in address;
- u_long _true = 1;
+ ioctlarg_t _true = 1;
int i = 1;
*err = 0;
@@ -893,7 +898,7 @@ NET_IP6Socket
int NET_IP6Socket( char *net_interface, int port, struct sockaddr_in6 *bindto, int *err ) {
SOCKET newsocket;
struct sockaddr_in6 address;
- u_long _true = 1;
+ ioctlarg_t _true = 1;
*err = 0;
@@ -1496,6 +1501,8 @@ static qboolean NET_GetCvars( void ) {
modified += net_socksPassword->modified;
net_socksPassword->modified = qfalse;
+ net_dropsim = Cvar_Get("net_dropsim", "", CVAR_TEMP);
+
return modified ? qtrue : qfalse;
}
@@ -1624,6 +1631,42 @@ void NET_Shutdown( void ) {
#endif
}
+/*
+====================
+NET_Event
+
+Called from NET_Sleep which uses select() to determine which sockets have seen action.
+====================
+*/
+
+void NET_Event(fd_set *fdr)
+{
+ byte bufData[MAX_MSGLEN + 1];
+ netadr_t from;
+ msg_t netmsg;
+
+ while(1)
+ {
+ MSG_Init(&netmsg, bufData, sizeof(bufData));
+
+ if(NET_GetPacket(&from, &netmsg, fdr))
+ {
+ if(net_dropsim->value > 0.0f && net_dropsim->value <= 100.0f)
+ {
+ // com_dropsim->value percent of incoming packets get dropped.
+ if(rand() < (int) (((double) RAND_MAX) / 100.0 * (double) net_dropsim->value))
+ continue; // drop this packet
+ }
+
+ if(com_sv_running->integer)
+ Com_RunAndTimeServerPacket(&from, &netmsg);
+ else
+ CL_PacketEvent(from, &netmsg);
+ }
+ else
+ break;
+ }
+}
/*
====================
@@ -1632,31 +1675,23 @@ NET_Sleep
Sleeps msec or until something happens on the network
====================
*/
-void NET_Sleep( int msec ) {
+void NET_Sleep(int msec)
+{
struct timeval timeout;
- fd_set fdset;
- int highestfd = -1;
-
- if (!com_dedicated->integer)
- return; // we're not a server, just run full speed
-
- if (ip_socket == INVALID_SOCKET && ip6_socket == INVALID_SOCKET)
- return;
-
- if (msec < 0 )
- return;
+ fd_set fdr;
+ int highestfd = -1, retval;
- FD_ZERO(&fdset);
+ FD_ZERO(&fdr);
if(ip_socket != INVALID_SOCKET)
{
- FD_SET(ip_socket, &fdset);
+ FD_SET(ip_socket, &fdr);
highestfd = ip_socket;
}
if(ip6_socket != INVALID_SOCKET)
{
- FD_SET(ip6_socket, &fdset);
+ FD_SET(ip6_socket, &fdr);
if(ip6_socket > highestfd)
highestfd = ip6_socket;
@@ -1664,9 +1699,23 @@ void NET_Sleep( int msec ) {
timeout.tv_sec = msec/1000;
timeout.tv_usec = (msec%1000)*1000;
- select(highestfd + 1, &fdset, NULL, NULL, &timeout);
-}
+
+#ifdef _WIN32
+ if(highestfd < 0)
+ {
+ // windows ain't happy when select is called without valid FDs
+ SleepEx(msec, 0);
+ return;
+ }
+#endif
+ retval = select(highestfd + 1, &fdr, NULL, NULL, &timeout);
+
+ if(retval < 0)
+ Com_Printf("Warning: select() syscall failed: %s\n", NET_ErrorString());
+ else if(retval > 0)
+ NET_Event(&fdr);
+}
/*
====================
diff --git a/src/qcommon/q_platform.h b/src/qcommon/q_platform.h
index 4d4d2856..3e9619ee 100644
--- a/src/qcommon/q_platform.h
+++ b/src/qcommon/q_platform.h
@@ -155,11 +155,16 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//================================================================= LINUX ===
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD_kernel__)
#include <endian.h>
+#if defined(__linux__)
#define OS_STRING "linux"
+#else
+#define OS_STRING "kFreeBSD"
+#endif
+
#define ID_INLINE inline
#define PATH_SEP '/'
diff --git a/src/qcommon/q_shared.c b/src/qcommon/q_shared.c
index ce28f953..8b13aba2 100644
--- a/src/qcommon/q_shared.c
+++ b/src/qcommon/q_shared.c
@@ -706,10 +706,6 @@ char* Q_strrchr( const char* string, int c )
qboolean Q_isanumber( const char *s )
{
-#ifdef Q3_VM
- //FIXME: implement
- return qfalse;
-#else
char *p;
double d;
@@ -719,7 +715,6 @@ qboolean Q_isanumber( const char *s )
d = strtod( s, &p );
return *p == '\0';
-#endif
}
qboolean Q_isintegral( float f )
@@ -727,6 +722,39 @@ qboolean Q_isintegral( float f )
return (int)f == f;
}
+#ifdef _MSC_VER
+/*
+=============
+Q_vsnprintf
+
+Special wrapper function for Microsoft's broken _vsnprintf() function.
+MinGW comes with its own snprintf() which is not broken.
+=============
+*/
+
+int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap)
+{
+ int retval;
+
+ retval = _vsnprintf(str, size, format, ap);
+
+ if(retval < 0 || retval == size)
+ {
+ // Microsoft doesn't adhere to the C99 standard of vsnprintf,
+ // which states that the return value must be the number of
+ // bytes written if the output string had sufficient length.
+ //
+ // Obviously we cannot determine that value from Microsoft's
+ // implementation, so we have no choice but to return size.
+
+ str[size - 1] = '\0';
+ return size;
+ }
+
+ return retval;
+}
+#endif
+
/*
=============
Q_strncpyz
@@ -954,28 +982,18 @@ void Q_ParseNewlines( char *dest, const char *src, int destsize )
*dest++ = '\0';
}
-void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) {
+void QDECL Com_sprintf(char *dest, int size, const char *fmt, ...)
+{
int len;
va_list argptr;
- char bigbuffer[32000]; // big, but small enough to fit in PPC stack
va_start (argptr,fmt);
- len = Q_vsnprintf (bigbuffer, sizeof(bigbuffer), fmt,argptr);
+ len = Q_vsnprintf(dest, size, fmt, argptr);
va_end (argptr);
- if ( len >= sizeof( bigbuffer ) ) {
- Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" );
- }
- if (len >= size) {
- Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size);
-#ifdef _DEBUG
- __asm {
- int 3;
- }
-#endif
- }
- Q_strncpyz (dest, bigbuffer, size );
-}
+ if(len >= size)
+ Com_Printf("Com_sprintf: Output length %d too short, require %d bytes.\n", size, len);
+}
/*
============
@@ -1317,6 +1335,7 @@ void Info_SetValueForKey( char *s, const char *key, const char *value ) {
Info_SetValueForKey_Big
Changes or adds a key/value pair
+Includes and retains zero-length values
==================
*/
void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) {
@@ -1337,7 +1356,7 @@ void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) {
}
Info_RemoveKey_Big (s, key);
- if (!value || !strlen(value))
+ if (!value)
return;
Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h
index 3f2cb9d5..1cedf6a8 100644
--- a/src/qcommon/q_shared.h
+++ b/src/qcommon/q_shared.h
@@ -38,8 +38,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define Q3_VERSION PRODUCT_NAME " " PRODUCT_VERSION
#define GAMENAME_FOR_MASTER "Tremulous"
+#define HEARTBEAT_FOR_MASTER GAMENAME_FOR_MASTER
+#define FLATLINE_FOR_MASTER GAMENAME_FOR_MASTER "dead"
#define MAX_TEAMNAME 32
+#define MAX_MASTER_SERVERS 5 // number of supported master servers
+
+#define DEMOEXT "dm_" // standard demo extension
#ifdef _MSC_VER
@@ -118,16 +123,6 @@ typedef int intptr_t;
#include <ctype.h>
#include <limits.h>
-// vsnprintf is ISO/IEC 9899:1999
-// abstracting this to make it portable
-#ifdef _WIN32
- #define Q_vsnprintf _vsnprintf
- #define Q_snprintf _snprintf
-#else
- #define Q_vsnprintf vsnprintf
- #define Q_snprintf snprintf
-#endif
-
#ifdef _MSC_VER
#include <io.h>
@@ -139,8 +134,15 @@ typedef int intptr_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int8 uint8_t;
+
+ // vsnprintf is ISO/IEC 9899:1999
+ // abstracting this to make it portable
+ int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap);
#else
#include <stdint.h>
+
+ #define Q_vsnprintf vsnprintf
+ #define Q_snprintf snprintf
#endif
#endif
@@ -165,12 +167,13 @@ typedef int sfxHandle_t;
typedef int fileHandle_t;
typedef int clipHandle_t;
-#define PAD(x,y) (((x)+(y)-1) & ~((y)-1))
+#define PAD(x,y) (((x)+(y)-1) & ~((y)-1))
+#define PADLEN(x,y) (PAD((x), (y)) - (x))
#ifdef __GNUC__
-#define ALIGN(x) __attribute__((aligned(x)))
+#define QALIGN(x) __attribute__((aligned(x)))
#else
-#define ALIGN(x)
+#define QALIGN(x)
#endif
#ifndef NULL
@@ -184,7 +187,7 @@ typedef int clipHandle_t;
#define MAX_QINT 0x7fffffff
#define MIN_QINT (-MAX_QINT-1)
-#define ARRAY_LEN(x) (sizeof(x) / sizeof(*x))
+#define ARRAY_LEN(x) (sizeof(x) / sizeof(*(x)))
// angle indexes
@@ -886,6 +889,7 @@ default values.
#define CVAR_SERVER_CREATED 0x0800 // cvar was created by a server the client connected to.
#define CVAR_VM_CREATED 0x1000 // cvar was created exclusively in one of the VMs.
+#define CVAR_PROTECTED 0x2000 // prevent modifying this var from VMs or the server
#define CVAR_NONEXISTENT 0xFFFFFFFF // Cvar doesn't exist.
// nothing outside the Cvar_*() functions should modify these fields!
@@ -1414,4 +1418,7 @@ typedef struct
#define DLP_PROMPTED 0x20 // prompt has been processed by client
#define DLP_STALE 0x40 // prompt is not being shown by UI VM
+#define LERP( a, b, w ) ( ( a ) * ( 1.0f - ( w ) ) + ( b ) * ( w ) )
+#define LUMA( red, green, blue ) ( 0.2126f * ( red ) + 0.7152f * ( green ) + 0.0722f * ( blue ) )
+
#endif // __Q_SHARED_H
diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h
index 09132159..d09ee299 100644
--- a/src/qcommon/qcommon.h
+++ b/src/qcommon/qcommon.h
@@ -416,6 +416,9 @@ void Cmd_RemoveCommand( const char *cmd_name );
typedef void (*completionFunc_t)( char *args, int argNum );
+// don't allow VMs to remove system commands
+void Cmd_RemoveCommandSafe( const char *cmd_name );
+
void Cmd_CommandCompletion( void(*callback)(const char *s) );
// callback with each valid string
void Cmd_SetCommandCompletionFunc( const char *command,
@@ -431,6 +434,7 @@ char *Cmd_ArgsFrom( int arg );
void Cmd_ArgsBuffer( char *buffer, int bufferLength );
void Cmd_LiteralArgsBuffer( char *buffer, int bufferLength );
char *Cmd_Cmd (void);
+void Cmd_Args_Sanitize( void );
// The functions that execute commands get their parameters with these
// functions. Cmd_Argv () will return an empty string, not a NULL
// if arg > argc, so string operations are allways safe.
@@ -489,11 +493,15 @@ void Cvar_Update( vmCvar_t *vmCvar );
void Cvar_Set( const char *var_name, const char *value );
// will create the variable with no flags if it doesn't exist
+void Cvar_SetSafe( const char *var_name, const char *value );
+// sometimes we set variables from an untrusted source: fail if flags & CVAR_PROTECTED
+
void Cvar_SetLatched( const char *var_name, const char *value);
// don't set the cvar immediately
void Cvar_SetValue( const char *var_name, float value );
-// expands value to a string and calls Cvar_Set
+void Cvar_SetValueSafe( const char *var_name, float value );
+// expands value to a string and calls Cvar_Set/Cvar_SetSafe
float Cvar_VariableValue( const char *var_name );
int Cvar_VariableIntegerValue( const char *var_name );
@@ -561,8 +569,6 @@ issues.
#define FS_UI_REF 0x02
#define FS_CGAME_REF 0x04
#define FS_QAGAME_REF 0x08
-// number of id paks that will never be autodownloaded from baseq3
-#define NUM_ID_PAKS 9
#define MAX_FILE_HANDLES 64
@@ -595,6 +601,9 @@ void FS_FreeFileList( char **list );
qboolean FS_FileExists( const char *file );
qboolean FS_CreatePath (char *OSPath);
+
+char *FS_FindDll( const char *filename );
+
char *FS_BuildOSPath( const char *base, const char *game, const char *qpath );
qboolean FS_CompareZipChecksum(const char *zipfile);
@@ -605,6 +614,7 @@ int FS_GetModList( char *listbuf, int bufsize );
fileHandle_t FS_FOpenFileWrite( const char *qpath );
fileHandle_t FS_FOpenFileAppend( const char *filename );
+fileHandle_t FS_FCreateOpenPipeFile( const char *filename );
// will properly create any needed paths and deal with seperater character issues
fileHandle_t FS_SV_FOpenFileWrite( const char *filename );
@@ -692,7 +702,6 @@ void FS_PureServerSetLoadedPaks( const char *pakSums, const char *pakNames );
// sole exception of .cfg files.
qboolean FS_CheckDirTraversal(const char *checkdir);
-qboolean FS_idPak( char *pak, char *base );
qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring );
void FS_Rename( const char *from, const char *to );
@@ -701,7 +710,9 @@ void FS_Remove( const char *osPath );
void FS_HomeRemove( const char *homePath );
void FS_FilenameCompletion( const char *dir, const char *ext,
- qboolean stripExt, void(*callback)(const char *s) );
+ qboolean stripExt, void(*callback)(const char *s), qboolean allowNonPureFilesOnDisk );
+
+const char *FS_GetCurrentGameDir(void);
/*
==============================================================
@@ -723,7 +734,7 @@ void Field_Clear( field_t *edit );
void Field_AutoComplete( field_t *edit );
void Field_CompleteKeyname( void );
void Field_CompleteFilename( const char *dir,
- const char *ext, qboolean stripExt );
+ const char *ext, qboolean stripExt, qboolean allowNonPureFilesOnDisk );
void Field_CompleteCommand( char *cmd,
qboolean doCommands, qboolean doCvars );
@@ -754,13 +765,12 @@ typedef enum
typedef enum {
// SE_NONE must be zero
- SE_NONE = 0, // evTime is still valid
- SE_KEY, // evValue is a key code, evValue2 is the down flag
- SE_CHAR, // evValue is an ascii char
- SE_MOUSE, // evValue and evValue2 are reletive signed x / y moves
+ SE_NONE = 0, // evTime is still valid
+ SE_KEY, // evValue is a key code, evValue2 is the down flag
+ SE_CHAR, // evValue is an ascii char
+ SE_MOUSE, // evValue and evValue2 are reletive signed x / y moves
SE_JOYSTICK_AXIS, // evValue is an axis number and evValue2 is the current state (-127 to 127)
- SE_CONSOLE, // evPtr is a char*
- SE_PACKET // evPtr is a netadr_t followed by data bytes to evPtrLength
+ SE_CONSOLE // evPtr is a char*
} sysEventType_t;
typedef struct {
@@ -793,6 +803,7 @@ int Com_Filter(char *filter, char *name, int casesensitive);
int Com_FilterPath(char *filter, char *name, int casesensitive);
int Com_RealTime(qtime_t *qtime);
qboolean Com_SafeMode( void );
+void Com_RunAndTimeServerPacket(netadr_t *evFrom, msg_t *buf);
void Com_StartupVariable( const char *match );
// checks for and removes command line "+set var arg" constructs
@@ -817,6 +828,7 @@ extern cvar_t *com_maxfpsUnfocused;
extern cvar_t *com_minimized;
extern cvar_t *com_maxfpsMinimized;
extern cvar_t *com_altivec;
+extern cvar_t *com_homepath;
// both client and server must agree to pause
extern cvar_t *cl_paused;
@@ -831,7 +843,6 @@ extern int time_frontend;
extern int time_backend; // renderer backend time
extern int com_frameTime;
-extern int com_frameMsec;
extern qboolean com_errorEntered;
@@ -976,6 +987,9 @@ void S_ClearSoundBuffer( void );
void SCR_DebugGraph (float value, int color); // FIXME: move logging to common?
+// AVI files have the start of pixel lines 4 byte-aligned
+#define AVI_LINE_PADDING 4
+
//
// server interface
//
@@ -983,6 +997,7 @@ void SV_Init( void );
void SV_Shutdown( char *finalmsg );
void SV_Frame( int msec );
void SV_PacketEvent( netadr_t from, msg_t *msg );
+int SV_FrameMsec(void);
qboolean SV_GameCommand( void );
@@ -1012,7 +1027,7 @@ typedef enum {
void Sys_Init (void);
// general development dll loading for virtual machine testing
-void * QDECL Sys_LoadDll( const char *name, char *fqpath , intptr_t (QDECL **entryPoint)(int, ...),
+void * QDECL Sys_LoadDll( const char *name, intptr_t (QDECL **entryPoint)(int, ...),
intptr_t (QDECL *systemcalls)(intptr_t, ...) );
void Sys_UnloadDll( void *dllHandle );
@@ -1053,7 +1068,6 @@ cpuFeatures_t Sys_GetProcessorFeatures( void );
void Sys_SetErrorText( const char *text );
void Sys_SendPacket( int length, const void *data, netadr_t to );
-qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message );
qboolean Sys_StringToAdr( const char *s, netadr_t *a, netadrtype_t family );
//Does NOT parse port numbers, only base addresses.
@@ -1062,6 +1076,7 @@ qboolean Sys_IsLANAddress (netadr_t adr);
void Sys_ShowIP(void);
qboolean Sys_Mkdir( const char *path );
+FILE *Sys_Mkfifo( const char *ospath );
char *Sys_Cwd( void );
void Sys_SetDefaultInstallPath(const char *path);
char *Sys_DefaultInstallPath(void);
diff --git a/src/qcommon/unzip.c b/src/qcommon/unzip.c
index d0b3d2a5..b307e98d 100644
--- a/src/qcommon/unzip.c
+++ b/src/qcommon/unzip.c
@@ -35,23 +35,10 @@ woven in by Terry Thorsen 1/2003.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include "../qcommon/q_shared.h"
+#include "../qcommon/qcommon.h"
#include "unzip.h"
-#ifdef STDC
-# include <stddef.h>
-# include <string.h>
-# include <stdlib.h>
-#endif
-#ifdef NO_ERRNO_H
- extern int errno;
-#else
-# include <errno.h>
-#endif
-
-
#ifndef local
# define local static
#endif
@@ -74,10 +61,10 @@ woven in by Terry Thorsen 1/2003.
#endif
#ifndef ALLOC
-# define ALLOC(size) (malloc(size))
+# define ALLOC(size) (Z_Malloc(size))
#endif
#ifndef TRYFREE
-# define TRYFREE(p) {if (p) free(p);}
+# define TRYFREE(p) {if (p) Z_Free(p);}
#endif
#define SIZECENTRALDIRITEM (0x2e)
diff --git a/src/qcommon/vm.c b/src/qcommon/vm.c
index 14fa32e9..225119fb 100644
--- a/src/qcommon/vm.c
+++ b/src/qcommon/vm.c
@@ -307,7 +307,7 @@ Dlls will call this directly
rcg010206 The horror; the horror.
- The syscall mechanism relies on stack manipulation to get it's args.
+ The syscall mechanism relies on stack manipulation to get its args.
This is likely due to C's inability to pass "..." parameters to
a function in one clean chunk. On PowerPC Linux, these parameters
are not necessarily passed on the stack, so while (&arg[0] == arg)
@@ -347,7 +347,7 @@ intptr_t QDECL VM_DllSyscall( intptr_t arg, ... ) {
args[0] = arg;
va_start(ap, arg);
- for (i = 1; i < sizeof (args) / sizeof (args[i]); i++)
+ for (i = 1; i < ARRAY_LEN (args); i++)
args[i] = va_arg(ap, intptr_t);
va_end(ap);
@@ -385,8 +385,8 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) {
return NULL;
}
- // show where the qvm was loaded from
- Cmd_ExecuteString( va( "which %s\n", filename ) );
+ // show where the qvm was loaded from
+ Cmd_ExecuteString( va( "which %s\n", filename ) );
if( LittleLong( header.h->vmMagic ) == VM_MAGIC_VER2 ) {
Com_Printf( "...which has vmMagic VM_MAGIC_VER2\n" );
@@ -560,7 +560,7 @@ vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *),
if ( interpret == VMI_NATIVE ) {
// try to load as a system dll
Com_Printf( "Loading dll file %s.\n", vm->name );
- vm->dllHandle = Sys_LoadDll( module, vm->fqpath , &vm->entryPoint, VM_DllSyscall );
+ vm->dllHandle = Sys_LoadDll( module, &vm->entryPoint, VM_DllSyscall );
if ( vm->dllHandle ) {
return vm;
}
@@ -757,7 +757,7 @@ intptr_t QDECL VM_Call( vm_t *vm, int callnum, ... ) {
int args[10];
va_list ap;
va_start(ap, callnum);
- for (i = 0; i < sizeof (args) / sizeof (args[i]); i++) {
+ for (i = 0; i < ARRAY_LEN(args); i++) {
args[i] = va_arg(ap, int);
}
va_end(ap);
@@ -782,7 +782,7 @@ intptr_t QDECL VM_Call( vm_t *vm, int callnum, ... ) {
a.callnum = callnum;
va_start(ap, callnum);
- for (i = 0; i < sizeof (a.args) / sizeof (a.args[0]); i++) {
+ for (i = 0; i < ARRAY_LEN(a.args); i++) {
a.args[i] = va_arg(ap, int);
}
va_end(ap);
diff --git a/src/qcommon/vm_local.h b/src/qcommon/vm_local.h
index e9c3f7cc..80430be0 100644
--- a/src/qcommon/vm_local.h
+++ b/src/qcommon/vm_local.h
@@ -169,8 +169,6 @@ struct vm_s {
int breakFunction; // increment breakCount on function entry to this
int breakCount;
- char fqpath[MAX_QPATH+1] ;
-
byte *jumpTableTargets;
int numJumpTableTargets;
};
diff --git a/src/qcommon/vm_powerpc.c b/src/qcommon/vm_powerpc.c
index 6b7404dc..831e5672 100644
--- a/src/qcommon/vm_powerpc.c
+++ b/src/qcommon/vm_powerpc.c
@@ -690,7 +690,7 @@ static const long int gpr_list[] = {
r7, r8, r9, r10,
};
static const long int gpr_vstart = 8; /* position of first volatile register */
-static const long int gpr_total = sizeof( gpr_list ) / sizeof( gpr_list[0] );
+static const long int gpr_total = ARRAY_LEN( gpr_list );
static const long int fpr_list[] = {
/* static registers, normally none is used */
@@ -704,7 +704,7 @@ static const long int fpr_list[] = {
f12, f13,
};
static const long int fpr_vstart = 8;
-static const long int fpr_total = sizeof( fpr_list ) / sizeof( fpr_list[0] );
+static const long int fpr_total = ARRAY_LEN( fpr_list );
/*
* prepare some dummy structures and emit init code
@@ -1837,7 +1837,7 @@ PPC_ComputeCode( vm_t *vm )
unsigned char *dataAndCode = mmap( NULL, codeLength,
PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0 );
- if ( ! dataAndCode )
+ if (dataAndCode == MAP_FAILED)
DIE( "Not enough memory" );
ppc_instruction_t *codeNow, *codeBegin;
diff --git a/src/qcommon/vm_powerpc_asm.c b/src/qcommon/vm_powerpc_asm.c
index da6a8434..58d65a00 100644
--- a/src/qcommon/vm_powerpc_asm.c
+++ b/src/qcommon/vm_powerpc_asm.c
@@ -39,6 +39,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
+#include "vm_local.h"
#include "vm_powerpc_asm.h"
#include <string.h>
@@ -389,8 +390,7 @@ static const struct powerpc_operand powerpc_operands[] =
};
-static const unsigned int num_powerpc_operands =
- (sizeof (powerpc_operands) / sizeof (powerpc_operands[0]));
+static const unsigned int num_powerpc_operands = ARRAY_LEN (powerpc_operands);
/* The functions used to insert and extract complicated operands. */
@@ -1004,6 +1004,3 @@ static const struct powerpc_opcode powerpc_opcodes[] = {
{ "fsub", A(63,20,0), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } },
{ "fneg", XRC(63,40,0), XRA_MASK, COM, { FRT, FRB } },
};
-
-static const int powerpc_num_opcodes =
- sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]);
diff --git a/src/qcommon/vm_sparc.c b/src/qcommon/vm_sparc.c
index 69bbdc5f..370ee200 100644
--- a/src/qcommon/vm_sparc.c
+++ b/src/qcommon/vm_sparc.c
@@ -259,7 +259,7 @@ static const struct sparc_opcode sparc_opcodes[] = {
{ "fbg", BFCC(0,6), { ARG_DISP22 }, },
{ "fble", BFCC(0,13), { ARG_DISP22 }, },
};
-#define SPARC_NUM_OPCODES (sizeof(sparc_opcodes) / sizeof(sparc_opcodes[0]))
+#define SPARC_NUM_OPCODES (ARRAY_LEN(sparc_opcodes))
#define RS1(X) (((X) & 0x1f) << 14)
#define RS2(X) (((X) & 0x1f) << 0)
@@ -320,7 +320,7 @@ static unsigned int sparc_assemble(enum sparc_iname iname, const int argc, const
#define IN(inst, args...) \
({ const int argv[] = { args }; \
- const int argc = sizeof(argv) / sizeof(argv[0]); \
+ const int argc = ARRAY_LEN(argv); \
sparc_assemble(inst, argc, argv); \
})
@@ -1427,7 +1427,7 @@ static void sparc_compute_code(vm_t *vm, struct func_info * const fp)
data_and_code = mmap(NULL, code_length, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
- if (!data_and_code)
+ if (data_and_code == MAP_FAILED)
DIE("Not enough memory");
code_now = code_begin = (unsigned int *)
diff --git a/src/qcommon/vm_x86.c b/src/qcommon/vm_x86.c
index 41806f2a..f25be998 100644
--- a/src/qcommon/vm_x86.c
+++ b/src/qcommon/vm_x86.c
@@ -54,6 +54,7 @@ static void VM_Destroy_Compiled(vm_t* self);
*/
+#define VMFREE_BUFFERS() do {Z_Free(buf); Z_Free(jused);} while(0)
static byte *buf = NULL;
static byte *jused = NULL;
static int compiledOfs = 0;
@@ -290,6 +291,7 @@ static int Hex( int c ) {
return c - '0';
}
+ VMFREE_BUFFERS();
Com_Error( ERR_DROP, "Hex: bad char '%c'", c );
return 0;
@@ -409,6 +411,7 @@ qboolean EmitMovEBXEDI(vm_t *vm, int andit) {
#define JUSED(x) \
do { \
if (x < 0 || x >= jusedSize) { \
+ VMFREE_BUFFERS(); \
Com_Error( ERR_DROP, \
"VM_CompileX86: jump target out of range at offset %d", pc ); \
} \
@@ -430,7 +433,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
// allocate a very large temp buffer, we will shrink it later
maxLength = header->codeLength * 8;
- buf = Z_Malloc( maxLength );
+ buf = Z_Malloc(maxLength);
jused = Z_Malloc(jusedSize);
Com_Memset(jused, 0, jusedSize);
@@ -455,16 +458,21 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
LastCommand = LAST_COMMAND_NONE;
- while ( instruction < header->instructionCount ) {
- if ( compiledOfs > maxLength - 16 ) {
- Com_Error( ERR_FATAL, "VM_CompileX86: maxLength exceeded" );
+ while(instruction < header->instructionCount)
+ {
+ if(compiledOfs > maxLength - 16)
+ {
+ VMFREE_BUFFERS();
+ Com_Error(ERR_DROP, "VM_CompileX86: maxLength exceeded");
}
vm->instructionPointers[ instruction ] = compiledOfs;
instruction++;
- if ( pc > header->codeLength ) {
- Com_Error( ERR_FATAL, "VM_CompileX86: pc > header->codeLength" );
+ if(pc > header->codeLength)
+ {
+ VMFREE_BUFFERS();
+ Com_Error(ERR_DROP, "VM_CompileX86: pc > header->codeLength");
}
op = code[ pc ];
@@ -1076,7 +1084,8 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
Emit4( (int)vm->instructionPointers );
break;
default:
- Com_Error( ERR_DROP, "VM_CompileX86: bad opcode %i at offset %i", op, pc );
+ VMFREE_BUFFERS();
+ Com_Error(ERR_DROP, "VM_CompileX86: bad opcode %i at offset %i", op, pc);
}
pop0 = pop1;
pop1 = op;
@@ -1087,13 +1096,13 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
vm->codeLength = compiledOfs;
#ifdef VM_X86_MMAP
vm->codeBase = mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
- if(vm->codeBase == (void*)-1)
- Com_Error(ERR_DROP, "VM_CompileX86: can't mmap memory");
+ if(vm->codeBase == MAP_FAILED)
+ Com_Error(ERR_FATAL, "VM_CompileX86: can't mmap memory");
#elif _WIN32
// allocate memory with EXECUTE permissions under windows.
vm->codeBase = VirtualAlloc(NULL, compiledOfs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(!vm->codeBase)
- Com_Error(ERR_DROP, "VM_CompileX86: VirtualAlloc failed");
+ Com_Error(ERR_FATAL, "VM_CompileX86: VirtualAlloc failed");
#else
vm->codeBase = malloc(compiledOfs);
#endif
@@ -1102,14 +1111,14 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
#ifdef VM_X86_MMAP
if(mprotect(vm->codeBase, compiledOfs, PROT_READ|PROT_EXEC))
- Com_Error(ERR_DROP, "VM_CompileX86: mprotect failed");
+ Com_Error(ERR_FATAL, "VM_CompileX86: mprotect failed");
#elif _WIN32
{
DWORD oldProtect = 0;
// remove write permissions.
if(!VirtualProtect(vm->codeBase, compiledOfs, PAGE_EXECUTE_READ, &oldProtect))
- Com_Error(ERR_DROP, "VM_CompileX86: VirtualProtect failed");
+ Com_Error(ERR_FATAL, "VM_CompileX86: VirtualProtect failed");
}
#endif
diff --git a/src/qcommon/vm_x86_64.c b/src/qcommon/vm_x86_64.c
index 13c39172..6b335447 100644
--- a/src/qcommon/vm_x86_64.c
+++ b/src/qcommon/vm_x86_64.c
@@ -55,6 +55,8 @@ static FILE* qdasmout;
#define Dfprintf(args...)
#endif
+#define VM_FREEBUFFERS(vm) do {assembler_init(0); VM_Destroy_Compiled(vm);} while(0)
+
void assembler_set_output(char* buf);
size_t assembler_get_code_size(void);
void assembler_init(int pass);
@@ -252,6 +254,7 @@ void emit(const char* fmt, ...)
#define CHECK_INSTR(nr) \
do { if(nr < 0 || nr >= header->instructionCount) { \
+ VM_FREEBUFFERS(vm); \
Com_Error( ERR_DROP, \
"%s: jump target 0x%x out of range at offset %d", __func__, nr, pc ); \
} } while(0)
@@ -430,6 +433,8 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
// const optimization
unsigned got_const = 0, const_value = 0;
+
+ vm->codeBase = NULL;
gettimeofday(&tvstart, NULL);
@@ -442,15 +447,17 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
#ifdef VM_X86_64_MMAP
vm->codeBase = mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
- if(vm->codeBase == (void*)-1)
- Com_Error(ERR_DROP, "VM_CompileX86: can't mmap memory");
+ if(vm->codeBase == MAP_FAILED)
+ Com_Error(ERR_FATAL, "VM_CompileX86_64: can't mmap memory");
#elif __WIN64__
// allocate memory with write permissions under windows.
vm->codeBase = VirtualAlloc(NULL, compiledOfs, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
if(!vm->codeBase)
- Com_Error(ERR_DROP, "VM_CompileX86: VirtualAlloc failed");
+ Com_Error(ERR_FATAL, "VM_CompileX86_64: VirtualAlloc failed");
#else
vm->codeBase = malloc(compiledOfs);
+ if(!vm_codeBase)
+ Com_Error(ERR_FATAL, "VM_CompileX86_64: Failed to allocate memory");
#endif
assembler_set_output((char*)vm->codeBase);
@@ -931,7 +938,9 @@ emit_do_syscall:
}
- if(got_const) {
+ if(got_const)
+ {
+ VM_FREEBUFFERS(vm);
Com_Error(ERR_DROP, "leftover const\n");
}
@@ -944,14 +953,14 @@ emit_do_syscall:
#ifdef VM_X86_64_MMAP
if(mprotect(vm->codeBase, compiledOfs, PROT_READ|PROT_EXEC))
- Com_Error(ERR_DROP, "VM_CompileX86: mprotect failed");
+ Com_Error(ERR_FATAL, "VM_CompileX86_64: mprotect failed");
#elif __WIN64__
{
DWORD oldProtect = 0;
// remove write permissions; give exec permision
if(!VirtualProtect(vm->codeBase, compiledOfs, PAGE_EXECUTE_READ, &oldProtect))
- Com_Error(ERR_DROP, "VM_CompileX86: VirtualProtect failed");
+ Com_Error(ERR_FATAL, "VM_CompileX86_64: VirtualProtect failed");
}
#endif
@@ -988,11 +997,16 @@ emit_do_syscall:
void VM_Destroy_Compiled(vm_t* self)
{
-#ifdef _WIN32
- VirtualFree(self->codeBase, 0, MEM_RELEASE);
+ if(self && self->codeBase)
+ {
+#ifdef VM_X86_64_MMAP
+ munmap(self->codeBase, self->codeLength);
+#elif __WIN64__
+ VirtualFree(self->codeBase, 0, MEM_RELEASE);
#else
- munmap(self->codeBase, self->codeLength);
+ free(self->codeBase);
#endif
+ }
}
/*
diff --git a/src/qcommon/vm_x86_64_assembler.c b/src/qcommon/vm_x86_64_assembler.c
index 99d2898e..06695d8d 100644
--- a/src/qcommon/vm_x86_64_assembler.c
+++ b/src/qcommon/vm_x86_64_assembler.c
@@ -22,6 +22,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
+#define _ISOC99_SOURCE
+
+#include "vm_local.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -240,9 +243,15 @@ static void hash_add_label(const char* label, unsigned address)
{
struct hashentry* h;
unsigned i = hashkey(label, -1U);
- i %= sizeof(labelhash)/sizeof(labelhash[0]);
- h = malloc(sizeof(struct hashentry));
- h->label = strdup(label);
+ int labellen;
+
+ i %= ARRAY_LEN(labelhash);
+ h = Z_Malloc(sizeof(struct hashentry));
+
+ labellen = strlen(label) + 1;
+ h->label = Z_Malloc(labellen);
+ memcpy(h->label, label, labellen);
+
h->address = address;
h->next = labelhash[i];
labelhash[i] = h;
@@ -252,7 +261,7 @@ static unsigned lookup_label(const char* label)
{
struct hashentry* h;
unsigned i = hashkey(label, -1U);
- i %= sizeof(labelhash)/sizeof(labelhash[0]);
+ i %= ARRAY_LEN(labelhash);
for(h = labelhash[i]; h; h = h->next )
{
if(!strcmp(h->label, label))
@@ -268,15 +277,15 @@ static void labelhash_free(void)
struct hashentry* h;
unsigned i;
unsigned z = 0, min = -1U, max = 0, t = 0;
- for ( i = 0; i < sizeof(labelhash)/sizeof(labelhash[0]); ++i)
+ for ( i = 0; i < ARRAY_LEN(labelhash); ++i)
{
unsigned n = 0;
h = labelhash[i];
while(h)
{
struct hashentry* next = h->next;
- free(h->label);
- free(h);
+ Z_Free(h->label);
+ Z_Free(h);
h = next;
++n;
}
@@ -286,7 +295,7 @@ static void labelhash_free(void)
min = MIN(min, n);
max = MAX(max, n);
}
- printf("total %u, hsize %"PRIu64", zero %u, min %u, max %u\n", t, sizeof(labelhash)/sizeof(labelhash[0]), z, min, max);
+ printf("total %u, hsize %"PRIu64", zero %u, min %u, max %u\n", t, ARRAY_LEN(labelhash), z, min, max);
memset(labelhash, 0, sizeof(labelhash));
}
@@ -1008,7 +1017,7 @@ static op_t* getop(const char* n)
#else
unsigned m, t, b;
int r;
- t = sizeof(ops)/sizeof(ops[0])-1;
+ t = ARRAY_LEN(ops)-1;
b = 0;
while(b <= t)
@@ -1299,7 +1308,7 @@ void assembler_init(int pass)
if(!ops_sorted)
{
ops_sorted = 1;
- qsort(ops, sizeof(ops)/sizeof(ops[0])-1, sizeof(ops[0]), opsort);
+ qsort(ops, ARRAY_LEN(ops)-1, sizeof(ops[0]), opsort);
}
}