Exemple #1
0
/*
* SV_FinalMessage
* 
* Used by SV_ShutdownGame to send a final message to all
* connected clients before the server goes down.  The messages are sent immediately,
* not just stuck on the outgoing message list, because the server is going
* to totally exit after returning from this function.
*/
static void SV_FinalMessage( const char *message, qboolean reconnect )
{
	int i, j;
	client_t *cl;

	for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
	{
		if( cl->edict && ( cl->edict->r.svflags & SVF_FAKECLIENT ) )
			continue;
		if( cl->state >= CS_CONNECTING )
		{
			if( reconnect )
				SV_SendServerCommand( cl, "forcereconnect \"%s\"", message );
			else
				SV_SendServerCommand( cl, "disconnect %i \"%s\"", DROP_TYPE_GENERAL, message );

			SV_InitClientMessage( cl, &tmpMessage, NULL, 0 );
			SV_AddReliableCommandsToMessage( cl, &tmpMessage );

			// send it twice
			for( j = 0; j < 2; j++ )
				SV_SendMessageToClient( cl, &tmpMessage );
		}
	}
}
Exemple #2
0
/*
* SV_Demo_WriteSnap
*/
void SV_Demo_WriteSnap( void )
{
	int i;
	msg_t msg;
	uint8_t msg_buffer[MAX_MSGLEN];

	if( !svs.demo.file )
		return;

	for( i = 0; i < sv_maxclients->integer; i++ )
	{
		if( svs.clients[i].state >= CS_SPAWNED && svs.clients[i].edict &&
			!( svs.clients[i].edict->r.svflags & SVF_NOCLIENT ) )
			break;
	}
	if( i == sv_maxclients->integer )
	{                               // FIXME
		Com_Printf( "No players left, stopping server side demo recording\n" );
		SV_Demo_Stop_f();
		return;
	}

	MSG_Init( &msg, msg_buffer, sizeof( msg_buffer ) );

	SV_BuildClientFrameSnap( &svs.demo.client );

	SV_WriteFrameSnapToClient( &svs.demo.client, &msg );

	SV_AddReliableCommandsToMessage( &svs.demo.client, &msg );

	SV_Demo_WriteMessage( &msg );

	svs.demo.duration = svs.gametime - svs.demo.basetime;
	svs.demo.client.lastframe = sv.framenum; // FIXME: is this needed?
}
Exemple #3
0
/*
* SV_DenyDownload
* Helper function for generating initdownload packets for denying download
*/
static void SV_DenyDownload( client_t *client, const char *reason )
{
	// size -1 is used to signal that it's refused
	// URL field is used for deny reason
	SV_InitClientMessage( client, &tmpMessage, NULL, 0 );
	SV_SendServerCommand( client, "initdownload \"%s\" %i %u %i \"%s\"", "", -1, 0, qfalse, reason ? reason : "" );
	SV_AddReliableCommandsToMessage( client, &tmpMessage );
	SV_SendMessageToClient( client, &tmpMessage );
}
Exemple #4
0
/*
* SV_SendClientMessages
*/
void SV_SendClientMessages( void )
{
	int i;
	client_t *client;

	// send a message to each connected client
	for( i = 0, client = svs.clients; i < sv_maxclients->integer; i++, client++ )
	{
		if( client->state == CS_FREE || client->state == CS_ZOMBIE )
			continue;

		if( client->edict && ( client->edict->r.svflags & SVF_FAKECLIENT ) )
		{
			client->lastSentFrameNum = sv.framenum;
			continue;
		}

		if( !client->tvclient ) {
			SV_UpdateActivity();
		}

		if( client->state == CS_SPAWNED )
		{
			if( !SV_SendClientDatagram( client ) )
			{
				Com_Printf( "Error sending message to %s: %s\n", client->name, NET_ErrorString() );
				if( client->reliable )
				{
					SV_DropClient( client, DROP_TYPE_GENERAL, "Error sending message: %s\n", NET_ErrorString() );
				}
			}
		}
		else
		{
			// send pending reliable commands, or send heartbeats for not timing out
			if( client->reliableSequence > client->reliableAcknowledge ||
				svs.realtime - client->lastPacketSentTime > 1000 )
			{
				SV_InitClientMessage( client, &tmpMessage, NULL, 0 );
				SV_AddReliableCommandsToMessage( client, &tmpMessage );
				if( !SV_SendMessageToClient( client, &tmpMessage ) )
				{
					Com_Printf( "Error sending message to %s: %s\n", client->name, NET_ErrorString() );
					if( client->reliable )
					{
						SV_DropClient( client, DROP_TYPE_GENERAL, "Error sending message: %s\n", NET_ErrorString() );
					}
				}
			}
		}
	}
}
Exemple #5
0
/*
* SV_Baselines_f
*/
static void SV_Baselines_f( client_t *client )
{
	int start;
	entity_state_t nullstate;
	entity_state_t *base;

	Com_DPrintf( "Baselines() from %s\n", client->name );

	if( client->state != CS_CONNECTED )
	{
		Com_Printf( "baselines not valid -- already spawned\n" );
		return;
	}

	// handle the case of a level changing while a client was connecting
	if( atoi( Cmd_Argv( 1 ) ) != svs.spawncount )
	{
		Com_Printf( "SV_Baselines_f from different level\n" );
		SV_New_f( client );
		return;
	}

	start = atoi( Cmd_Argv( 2 ) );
	if( start < 0 )
		start = 0;

	memset( &nullstate, 0, sizeof( nullstate ) );

	// write a packet full of data
	SV_InitClientMessage( client, &tmpMessage, NULL, 0 );

	while( tmpMessage.cursize < FRAGMENT_SIZE * 3 && start < MAX_EDICTS )
	{
		base = &sv.baselines[start];
		if( base->modelindex || base->sound || base->effects )
		{
			MSG_WriteByte( &tmpMessage, svc_spawnbaseline );
			MSG_WriteDeltaEntity( &nullstate, base, &tmpMessage, qtrue, qtrue );
		}
		start++;
	}

	// send next command
	if( start == MAX_EDICTS )
		SV_SendServerCommand( client, "precache %i", svs.spawncount );
	else
		SV_SendServerCommand( client, "cmd baselines %i %i", svs.spawncount, start );

	SV_AddReliableCommandsToMessage( client, &tmpMessage );
	SV_SendMessageToClient( client, &tmpMessage );
}
Exemple #6
0
/*
* SV_SendClientDatagram
*/
static bool SV_SendClientDatagram( client_t *client )
{
	if( client->edict && ( client->edict->r.svflags & SVF_FAKECLIENT ) )
		return true;

	SV_InitClientMessage( client, &tmpMessage, NULL, 0 );

	SV_AddReliableCommandsToMessage( client, &tmpMessage );

	// send over all the relevant entity_state_t
	// and the player_state_t
	SV_BuildClientFrameSnap( client );

	SV_WriteFrameSnapToClient( client, &tmpMessage );

	return SV_SendMessageToClient( client, &tmpMessage );
}
Exemple #7
0
/*
* SV_BeginDownload_f
* Responds to reliable download packet with reliable initdownload packet
*/
static void SV_BeginDownload_f( client_t *client )
{
	const char *requestname;
	const char *uploadname;
	size_t alloc_size;
	unsigned checksum;
	char *url;
	const char *errormsg = NULL;
	qboolean allow, requestpak;
	qboolean local_http = SV_Web_Running() && sv_uploads_http->integer != 0;

	requestpak = ( atoi( Cmd_Argv( 1 ) ) == 1 );
	requestname = Cmd_Argv( 2 );

	if( !requestname[0] || !COM_ValidateRelativeFilename( requestname ) )
	{
		SV_DenyDownload( client, "Invalid filename" );
		return;
	}

	if( !SV_FilenameForDownloadRequest( requestname, requestpak, &uploadname, &errormsg ) ) {
		assert( errormsg != NULL );
		SV_DenyDownload( client, errormsg );
		return;
	}

	if( FS_CheckPakExtension( uploadname ) )
	{
		allow = qfalse;

		// allow downloading paks from the pure list, if not spawned
		if( client->state < CS_SPAWNED )
		{
			purelist_t *purefile;

			purefile = svs.purelist;
			while( purefile )
			{
				if( !strcmp( uploadname, purefile->filename ) )
				{
					allow = qtrue;
					break;
				}
				purefile = purefile->next;
			}
		}

		// game module has a change to allow extra downloads
		if( !allow && !SV_GameAllowDownload( client, requestname, uploadname ) )
		{
			SV_DenyDownload( client, "Downloading of this file is not allowed" );
			return;
		}
	}
	else
	{
		if( !SV_GameAllowDownload( client, requestname, uploadname ) )
		{
			SV_DenyDownload( client, "Downloading of this file is not allowed" );
			return;
		}
	}

	// we will just overwrite old download, if any
	if( client->download.name )
	{
		if( client->download.data )
		{
			FS_FreeBaseFile( client->download.data );
			client->download.data = NULL;
		}

		Mem_ZoneFree( client->download.name );
		client->download.name = NULL;

		client->download.size = 0;
		client->download.timeout = 0;
	}

	client->download.size = FS_LoadBaseFile( uploadname, NULL, NULL, 0 );
	if( client->download.size == -1 )
	{
		Com_Printf( "Error getting size of %s for uploading\n", uploadname );
		client->download.size = 0;
		SV_DenyDownload( client, "Error getting file size" );
		return;
	}

	checksum = FS_ChecksumBaseFile( uploadname );
	client->download.timeout = svs.realtime + 1000 * 60 * 60; // this is web download timeout

	alloc_size = sizeof( char ) * ( strlen( uploadname ) + 1 );
	client->download.name = Mem_ZoneMalloc( alloc_size );
	Q_strncpyz( client->download.name, uploadname, alloc_size );

	Com_Printf( "Offering %s to %s\n", client->download.name, client->name );

	if( FS_CheckPakExtension( uploadname ) && ( local_http || sv_uploads_baseurl->string[0] != 0 ) )
	{
		// .pk3 and .pak download from the web
		if( local_http )
		{
			url = TempCopyString( va( "files/%s", uploadname ) );
		}
		else
		{
			alloc_size = sizeof( char ) * ( strlen( sv_uploads_baseurl->string ) + 1 );
			url = Mem_TempMalloc( alloc_size );
			Q_snprintfz( url, alloc_size, "%s/", sv_uploads_baseurl->string );
		}
	}
	else if( SV_IsDemoDownloadRequest( requestname ) && ( local_http || sv_uploads_demos_baseurl->string[0] != 0 ) )
	{
		// demo file download from the web
		if( local_http )
		{
			url = TempCopyString( va( "files/%s", uploadname ) );
		}
		else
		{
			alloc_size = sizeof( char ) * ( strlen( sv_uploads_demos_baseurl->string ) + 1 );
			url = Mem_TempMalloc( alloc_size );
			Q_snprintfz( url, alloc_size, "%s/", sv_uploads_demos_baseurl->string );
		}
	}
	else
	{
		url = NULL;
	}

	// start the download
	SV_InitClientMessage( client, &tmpMessage, NULL, 0 );
	SV_SendServerCommand( client, "initdownload \"%s\" %i %u %i \"%s\"", client->download.name,
		client->download.size, checksum, local_http ? 1 : 0, ( url ? url : "" ) );
	SV_AddReliableCommandsToMessage( client, &tmpMessage );
	SV_SendMessageToClient( client, &tmpMessage );

	if( url )
	{
		Mem_TempFree( url );
		url = NULL;
	}
}
Exemple #8
0
/*
* SV_NextDownload_f
* 
* Responds to reliable nextdl packet with unreliable download packet
* If nextdl packet's offet information is negative, download will be stopped
*/
static void SV_NextDownload_f( client_t *client )
{
	int blocksize;
	int offset;

	if( !client->download.name )
	{
		Com_Printf( "nextdl message for client with no download active, from: %s\n", client->name );
		return;
	}

	if( Q_stricmp( client->download.name, Cmd_Argv( 1 ) ) )
	{
		Com_Printf( "nextdl message for wrong filename, from: %s\n", client->name );
		return;
	}

	offset = atoi( Cmd_Argv( 2 ) );

	if( offset > client->download.size )
	{
		Com_Printf( "nextdl message with too big offset, from: %s\n", client->name );
		return;
	}

	if( offset == -1 )
	{
		Com_Printf( "Upload of %s to %s%s completed\n", client->download.name, client->name, S_COLOR_WHITE );
		if( client->download.data )
		{
			FS_FreeBaseFile( client->download.data );
			client->download.data = NULL;
		}
		Mem_ZoneFree( client->download.name );
		client->download.name = NULL;
		client->download.size = 0;
		client->download.timeout = 0;
		return;
	}

	if( offset < 0 )
	{
		Com_Printf( "Upload of %s to %s%s failed\n", client->download.name, client->name, S_COLOR_WHITE );
		if( client->download.data )
		{
			FS_FreeBaseFile( client->download.data );
			client->download.data = NULL;
		}
		Mem_ZoneFree( client->download.name );
		client->download.name = NULL;
		client->download.size = 0;
		client->download.timeout = 0;
		return;
	}

	if( !client->download.data )
	{
		Com_Printf( "Starting server upload of %s to %s\n", client->download.name, client->name );

		FS_LoadBaseFile( client->download.name, (void **)&client->download.data, NULL, 0 );
		if( !client->download.data )
		{
			Com_Printf( "Error loading %s for uploading\n", client->download.name );
			Mem_ZoneFree( client->download.name );
			client->download.name = NULL;
			client->download.size = 0;
			client->download.timeout = 0;
			return;
		}
	}

	SV_InitClientMessage( client, &tmpMessage, NULL, 0 );
	SV_AddReliableCommandsToMessage( client, &tmpMessage );

	blocksize = client->download.size - offset;
	// jalfixme: adapt download to user rate setting and sv_maxrate setting.
	if( blocksize > FRAGMENT_SIZE * 2 )
		blocksize = FRAGMENT_SIZE * 2;
	if( offset + blocksize > client->download.size )
		blocksize = client->download.size - offset;

	MSG_WriteByte( &tmpMessage, svc_download );
	MSG_WriteString( &tmpMessage, client->download.name );
	MSG_WriteLong( &tmpMessage, offset );
	MSG_WriteLong( &tmpMessage, blocksize );
	MSG_CopyData( &tmpMessage, client->download.data + offset, blocksize );
	SV_SendMessageToClient( client, &tmpMessage );

	client->download.timeout = svs.realtime + 10000;
}
Exemple #9
0
/*
* SV_DropClient
* 
* Called when the player is totally leaving the server, either willingly
* or unwillingly.  This is NOT called if the entire server is quiting
* or crashing.
*/
void SV_DropClient( client_t *drop, int type, const char *format, ... )
{
	va_list	argptr;
	char *reason;
	char string[1024];

	if( format )
	{
		va_start( argptr, format );
		Q_vsnprintfz( string, sizeof( string ), format, argptr );
		va_end( argptr );
		reason = string;
	}
	else
	{
		Q_strncpyz( string, "User disconnected", sizeof( string ) );
		reason = NULL;
	}

	// remove the rating of the client
	if( drop->edict )
		ge->RemoveRating( drop->edict );

	// add the disconnect
	if( drop->edict && ( drop->edict->r.svflags & SVF_FAKECLIENT ) )
	{
		ge->ClientDisconnect( drop->edict, reason );
		SV_ClientResetCommandBuffers( drop ); // make sure everything is clean
	}
	else
	{
		SV_InitClientMessage( drop, &tmpMessage, NULL, 0 );
		SV_SendServerCommand( drop, "disconnect %i \"%s\"", type, string );
		SV_AddReliableCommandsToMessage( drop, &tmpMessage );

		SV_SendMessageToClient( drop, &tmpMessage );
		Netchan_PushAllFragments( &drop->netchan );

		if( drop->state >= CS_CONNECTED )
		{
			// call the prog function for removing a client
			// this will remove the body, among other things
			ge->ClientDisconnect( drop->edict, reason );
		}
		else if( drop->name[0] )
		{
			Com_Printf( "Connecting client %s%s disconnected (%s%s)\n", drop->name, S_COLOR_WHITE, reason,
				S_COLOR_WHITE );
		}
	}

	SV_MM_ClientDisconnect( drop );

	SNAP_FreeClientFrames( drop );

	if( drop->download.name )
	{
		if( drop->download.data )
		{
			FS_FreeBaseFile( drop->download.data );
			drop->download.data = NULL;
		}

		Mem_ZoneFree( drop->download.name );
		drop->download.name = NULL;

		drop->download.size = 0;
		drop->download.timeout = 0;
	}

	if( drop->individual_socket )
		NET_CloseSocket( &drop->socket );

	if( drop->mv )
	{
		sv.num_mv_clients--;
		drop->mv = qfalse;
	}

	drop->tvclient = qfalse;
	drop->state = CS_ZOMBIE;    // become free in a few seconds
	drop->name[0] = 0;
}
Exemple #10
0
/*
* SV_NextDownload_f
* 
* Responds to reliable nextdl packet with unreliable download packet
* If nextdl packet's offet information is negative, download will be stopped
*/
static void SV_NextDownload_f( client_t *client )
{
	int blocksize;
	int offset;
	uint8_t data[FRAGMENT_SIZE*2];

	if( !client->download.name )
	{
		Com_Printf( "nextdl message for client with no download active, from: %s\n", client->name );
		return;
	}

	if( Q_stricmp( client->download.name, Cmd_Argv( 1 ) ) )
	{
		Com_Printf( "nextdl message for wrong filename, from: %s\n", client->name );
		return;
	}

	offset = atoi( Cmd_Argv( 2 ) );

	if( offset > client->download.size )
	{
		Com_Printf( "nextdl message with too big offset, from: %s\n", client->name );
		return;
	}

	if( offset == -1 )
	{
		Com_Printf( "Upload of %s to %s%s completed\n", client->download.name, client->name, S_COLOR_WHITE );
		SV_ClientCloseDownload( client );
		return;
	}

	if( offset < 0 )
	{
		Com_Printf( "Upload of %s to %s%s failed\n", client->download.name, client->name, S_COLOR_WHITE );
		SV_ClientCloseDownload( client );
		return;
	}

	if( !client->download.file )
	{
		Com_Printf( "Starting server upload of %s to %s\n", client->download.name, client->name );

		client->download.size = FS_FOpenBaseFile( client->download.name, &client->download.file, FS_READ );
		if( !client->download.file || client->download.size < 0 )
		{
			Com_Printf( "Error opening %s for uploading\n", client->download.name );
			SV_ClientCloseDownload( client );
			return;
		}
	}

	SV_InitClientMessage( client, &tmpMessage, NULL, 0 );
	SV_AddReliableCommandsToMessage( client, &tmpMessage );

	blocksize = client->download.size - offset;
	// jalfixme: adapt download to user rate setting and sv_maxrate setting.
	if( blocksize > sizeof( data ) )
		blocksize = sizeof( data );
	if( offset + blocksize > client->download.size )
		blocksize = client->download.size - offset;
	if( blocksize < 0 )
		blocksize = 0;

	if( blocksize > 0 )
	{
		FS_Seek( client->download.file, offset, FS_SEEK_SET );
		blocksize = FS_Read( data, blocksize, client->download.file );
	}

	MSG_WriteByte( &tmpMessage, svc_download );
	MSG_WriteString( &tmpMessage, client->download.name );
	MSG_WriteLong( &tmpMessage, offset );
	MSG_WriteLong( &tmpMessage, blocksize );
	if( blocksize > 0 )
		MSG_CopyData( &tmpMessage, data, blocksize );
	SV_SendMessageToClient( client, &tmpMessage );

	client->download.timeout = svs.realtime + 10000;
}