diff options
Diffstat (limited to 'src/qcommon')
| -rw-r--r-- | src/qcommon/cmd.c | 77 | ||||
| -rw-r--r-- | src/qcommon/common.c | 266 | ||||
| -rw-r--r-- | src/qcommon/cvar.c | 53 | ||||
| -rw-r--r-- | src/qcommon/files.c | 298 | ||||
| -rw-r--r-- | src/qcommon/msg.c | 8 | ||||
| -rw-r--r-- | src/qcommon/net_ip.c | 107 | ||||
| -rw-r--r-- | src/qcommon/q_platform.h | 7 | ||||
| -rw-r--r-- | src/qcommon/q_shared.c | 63 | ||||
| -rw-r--r-- | src/qcommon/q_shared.h | 35 | ||||
| -rw-r--r-- | src/qcommon/qcommon.h | 45 | ||||
| -rw-r--r-- | src/qcommon/unzip.c | 21 | ||||
| -rw-r--r-- | src/qcommon/vm.c | 14 | ||||
| -rw-r--r-- | src/qcommon/vm_local.h | 2 | ||||
| -rw-r--r-- | src/qcommon/vm_powerpc.c | 6 | ||||
| -rw-r--r-- | src/qcommon/vm_powerpc_asm.c | 7 | ||||
| -rw-r--r-- | src/qcommon/vm_sparc.c | 6 | ||||
| -rw-r--r-- | src/qcommon/vm_x86.c | 33 | ||||
| -rw-r--r-- | src/qcommon/vm_x86_64.c | 32 | ||||
| -rw-r--r-- | src/qcommon/vm_x86_64_assembler.c | 29 | 
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);  	}  }  | 
