Esempio n. 1
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 -- SV_FinalCommand() will handle that
=====================
*/
void SV_DropClient( client_t *drop, const char *reason )
{
	if ( drop->state == clientState_t::CS_ZOMBIE )
	{
		return; // already dropped
	}
	Log::Debug( "Going to CS_ZOMBIE for %s", drop->name );
	drop->state = clientState_t::CS_ZOMBIE; // become free in a few seconds

	// call the prog function for removing a client
	// this will remove the body, among other things
	gvm.GameClientDisconnect( drop - svs.clients );

	if ( SV_IsBot(drop) )
	{
		SV_BotFreeClient( drop - svs.clients );
	}
	else
	{
		// tell everyone why they got dropped
		// Gordon: we want this displayed elsewhere now
		SV_SendServerCommand( nullptr, "print %s\"^* \"%s\"\n\"", Cmd_QuoteString( drop->name ), Cmd_QuoteString( reason ) );

		// add the disconnect command
		SV_SendServerCommand( drop, "disconnect %s\n", Cmd_QuoteString( reason ) );
	}

	// nuke user info
	SV_SetUserinfo( drop - svs.clients, "" );

	SV_FreeClient( drop );

	// if this was the last client on the server, send a heartbeat
	// to the master so it is known the server is empty
	// send a heartbeat now so the master will get up to date info
	// if there is already a slot for this IP address, reuse it
	int i;
	for ( i = 0; i < sv_maxclients->integer; i++ )
	{
		if ( svs.clients[ i ].state >= clientState_t::CS_CONNECTED )
		{
			break;
		}
	}

	if ( i == sv_maxclients->integer )
	{
		SV_Heartbeat_f();
	}
}
Esempio n. 2
0
/*
================
SV_Shutdown

Called when each game quits,
before Sys_Quit or Sys_Error
================
*/
void SV_Shutdown( const char *finalmsg )
{
	if ( !com_sv_running || !com_sv_running->integer )
	{
		return;
	}

	PrintBanner(_( "Server Shutdown" ))

	NET_LeaveMulticast6();

	if ( svs.clients && !com_errorEntered )
	{
		SV_FinalCommand( va( "print %s", Cmd_QuoteString( finalmsg ) ), qtrue );
	}

	SV_RemoveOperatorCommands();
	SV_MasterShutdown();
	SV_ShutdownGameProgs();

	// free current level
	SV_ClearServer();

	// free server static data
	if ( svs.clients )
	{
		int index;

		for ( index = 0; index < sv_maxclients->integer; index++ )
		{
			SV_FreeClient( &svs.clients[ index ] );
		}

		//Z_Free( svs.clients );
		free( svs.clients );  // RF, avoid trying to allocate large chunk on a fragmented zone
	}

	memset( &svs, 0, sizeof( svs ) );
	svs.serverLoad = -1;

	Cvar_Set( "sv_running", "0" );
#ifndef DEDICATED
	NET_Config( qtrue );
#endif

	Com_Printf( "---------------------------\n" );

	// disconnect any local clients
	CL_Disconnect( qfalse );
}
Esempio n. 3
0
/*
================
SV_Shutdown

Called when each game quits,
before Sys_Quit or Sys_Error
================
*/
void SV_Shutdown( const char *finalmsg )
{
	if ( !com_sv_running || !com_sv_running->integer )
	{
		return;
	}

	PrintBanner( "Server Shutdown" )

	NET_LeaveMulticast6();

	if ( svs.clients )
	{
		SV_FinalCommand( va( "print %s", Cmd_QuoteString( finalmsg ) ), true );
	}

	SV_RemoveOperatorCommands();
	SV_MasterShutdown();
	SV_ShutdownGameProgs();

	// free current level
	SV_ClearServer();

	// free server static data
	if ( svs.clients )
	{
		int index;

		for ( index = 0; index < sv_maxclients->integer; index++ )
		{
			SV_FreeClient( &svs.clients[ index ] );
		}

		free( svs.clients );
	}

	memset( &svs, 0, sizeof( svs ) );
	svs.serverLoad = -1;

	Cvar_Set( "sv_running", "0" );
#ifndef BUILD_SERVER
	NET_Config( true );
#endif

	Com_Printf( "---------------------------\n" );

	// disconnect any local clients
	CL_Disconnect( false );
}
Esempio n. 4
0
/*
============
Cvar_WriteVariables

Appends lines containing "set variable value" for all variables
with the archive flag set that are not in a transient state.
============
*/
void Cvar_WriteVariables( fileHandle_t f )
{
    cvar_t *var;
    char   buffer[ 1024 ];

    for ( var = cvar_vars; var; var = var->next )
    {
        if ( var->flags & CVAR_ARCHIVE )
        {
            if( var->transient )
                continue;

            // write the latched value, even if it hasn't taken effect yet
            Com_sprintf( buffer, sizeof( buffer ), "seta %s %s%s\n",
                         var->name,
                         Cmd_QuoteString( var->latchedString ? var->latchedString : var->string ),
                         ( var->flags & CVAR_UNSAFE ) ? " unsafe" : "" );

            FS_Printf( f, "%s", buffer );
        }
    }
}
Esempio n. 5
0
/*
===================
CL_GetServerCommand

Set up argc/argv for the given command
===================
*/
qboolean CL_GetServerCommand( int serverCommandNumber )
{
	const char  *s;
	char        *cmd;
	static char bigConfigString[ BIG_INFO_STRING ];
	int         argc;

	// if we have irretrievably lost a reliable command, drop the connection
	if ( serverCommandNumber <= clc.serverCommandSequence - MAX_RELIABLE_COMMANDS )
	{
		// when a demo record was started after the client got a whole bunch of
		// reliable commands then the client never got those first reliable commands
		if ( clc.demoplaying )
		{
			return qfalse;
		}

		Com_Error( ERR_DROP, "CL_GetServerCommand: a reliable command was cycled out" );
	}

	if ( serverCommandNumber > clc.serverCommandSequence )
	{
		Com_Error( ERR_DROP, "CL_GetServerCommand: requested a command not received" );
	}

	s = clc.serverCommands[ serverCommandNumber & ( MAX_RELIABLE_COMMANDS - 1 ) ];
	clc.lastExecutedServerCommand = serverCommandNumber;

	if ( cl_showServerCommands->integer )
	{
		// NERVE - SMF
		Com_Printf( "serverCommand: %i : %s\n", serverCommandNumber, s );
	}

rescan:
	Cmd_TokenizeString( s );
	cmd = Cmd_Argv( 0 );
	argc = Cmd_Argc();

	if ( !strcmp( cmd, "disconnect" ) )
	{
		// NERVE - SMF - allow server to indicate why they were disconnected
		if ( argc >= 2 )
		{
			Com_Error( ERR_SERVERDISCONNECT, "Server Disconnected – %s", Cmd_Argv( 1 ) );
		}
		else
		{
			Com_Error( ERR_SERVERDISCONNECT, "Server disconnected" );
		}
	}

	if ( !strcmp( cmd, "bcs0" ) )
	{
		Com_sprintf( bigConfigString, BIG_INFO_STRING, "cs %s %s", Cmd_Argv( 1 ), Cmd_QuoteString( Cmd_Argv( 2 ) ) );
		return qfalse;
	}

	if ( !strcmp( cmd, "bcs1" ) )
	{
		s = Cmd_QuoteString( Cmd_Argv( 2 ) );

		if ( strlen( bigConfigString ) + strlen( s ) >= BIG_INFO_STRING )
		{
			Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" );
		}

		strcat( bigConfigString, s );
		return qfalse;
	}

	if ( !strcmp( cmd, "bcs2" ) )
	{
		s = Cmd_QuoteString( Cmd_Argv( 2 ) );

		if ( strlen( bigConfigString ) + strlen( s ) + 1 >= BIG_INFO_STRING )
		{
			Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" );
		}

		strcat( bigConfigString, s );
		strcat( bigConfigString, "\"" );
		s = bigConfigString;
		goto rescan;
	}

	if ( !strcmp( cmd, "cs" ) )
	{
		CL_ConfigstringModified();
		// reparse the string, because CL_ConfigstringModified may have done another Cmd_TokenizeString()
		Cmd_TokenizeString( s );
		return qtrue;
	}

	if ( !strcmp( cmd, "map_restart" ) )
	{
		// clear notify lines and outgoing commands before passing
		// the restart to the cgame
		Con_ClearNotify();
		memset( cl.cmds, 0, sizeof( cl.cmds ) );
		return qtrue;
	}

	if ( !strcmp( cmd, "popup" ) )
	{
		// direct server to client popup request, bypassing cgame
//      trap_UI_Popup(Cmd_Argv(1));
//      if ( cls.state == CA_ACTIVE && !clc.demoplaying ) {
//          VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_CLIPBOARD);
//          Menus_OpenByName(Cmd_Argv(1));
//      }
		return qfalse;
	}

#ifdef USE_CRYPTO

	if ( cl_pubkeyID->integer && !strcmp( cmd, "pubkey_request" ) )
	{
		char buffer[ MAX_STRING_CHARS ] = "pubkey ";
		mpz_get_str( buffer + 7, 16, public_key.n );
		CL_AddReliableCommand( buffer );
		return qfalse;
	}

	if ( cl_pubkeyID->integer && !strcmp( cmd, "pubkey_decrypt" ) )
	{
		char         buffer[ MAX_STRING_CHARS ] = "pubkey_identify ";
		unsigned int msg_len = MAX_STRING_CHARS - 16;
		mpz_t        message;

		if ( argc == 1 )
		{
			Com_Printf("%s", _( "^3Server sent a pubkey_decrypt command, but sent nothing to decrypt!\n" ));
			return qfalse;
		}

		mpz_init_set_str( message, Cmd_Argv( 1 ), 16 );

		if ( rsa_decrypt( &private_key, &msg_len, ( unsigned char * ) buffer + 16, message ) )
		{
			nettle_mpz_set_str_256_u( message, msg_len, ( unsigned char * ) buffer + 16 );
			mpz_get_str( buffer + 16, 16, message );
			CL_AddReliableCommand( buffer );
		}

		mpz_clear( message );
		return qfalse;
	}

#endif

	// we may want to put a "connect to other server" command here

	// cgame can now act on the command
	return qtrue;
}
Esempio n. 6
0
void SV_UpdateConfigStrings()
{
	int      len, i, index;
	client_t *client;
	int      maxChunkSize = MAX_STRING_CHARS - 64;

	for ( index = 0; index < MAX_CONFIGSTRINGS; index++ )
	{
		if ( !sv.configstringsmodified[ index ] )
		{
			continue;
		}

		sv.configstringsmodified[ index ] = false;

		// send it to all the clients if we aren't
		// spawning a new server
		if ( sv.state == SS_GAME || sv.restarting )
		{
			// send the data to all relevent clients
			for ( i = 0, client = svs.clients; i < sv_maxclients->integer; i++, client++ )
			{
				if ( client->state < CS_PRIMED )
				{
					continue;
				}

				// do not always send server info to all clients
				if ( index == CS_SERVERINFO && client->gentity && ( client->gentity->r.svFlags & SVF_NOSERVERINFO ) )
				{
					continue;
				}

				len = strlen( sv.configstrings[ index ] );

				if ( len >= maxChunkSize )
				{
					int  sent = 0;
					int  remaining = len;
					const char *cmd;
					char buf[ MAX_STRING_CHARS ];

					while ( remaining > 0 )
					{
						if ( sent == 0 )
						{
							cmd = "bcs0";
						}
						else if ( remaining < maxChunkSize )
						{
							cmd = "bcs2";
						}
						else
						{
							cmd = "bcs1";
						}

						Q_strncpyz( buf, &sv.configstrings[ index ][ sent ], maxChunkSize );

						SV_SendServerCommand( client, "%s %i %s\n", cmd, index, Cmd_QuoteString( buf ) );

						sent += ( maxChunkSize - 1 );
						remaining -= ( maxChunkSize - 1 );
					}
				}
				else
				{
					// standard cs, just send it
					SV_SendServerCommand( client, "cs %i %s\n", index, Cmd_QuoteString( sv.configstrings[ index ] ) );
				}
			}
		}
	}
}
Esempio n. 7
0
/*
============
Cmd_QuoteStringBuffer

Cmd_QuoteString for VM usage
============
*/
void Cmd_QuoteStringBuffer( const char *in, char *buffer, int size )
{
	Q_strncpyz( buffer, Cmd_QuoteString( in ), size );
}
Esempio n. 8
0
/*
===================
CL_HandleServerCommand
CL_GetServerCommand
===================
*/
bool CL_HandleServerCommand(Str::StringRef text, std::string& newText) {
	static char bigConfigString[ BIG_INFO_STRING ];
	Cmd::Args args(text);

	if (args.Argc() == 0) {
		return false;
	}

	auto cmd = args.Argv(0);
	int argc = args.Argc();

	if (cmd == "disconnect") {
		// NERVE - SMF - allow server to indicate why they were disconnected
		if (argc >= 2) {
			Com_Error(errorParm_t::ERR_SERVERDISCONNECT, "Server disconnected: %s", args.Argv(1).c_str());
		} else {
			Com_Error(errorParm_t::ERR_SERVERDISCONNECT, "Server disconnected");
		}
	}

	// bcs0 to bcs2 are used by the server to send info strings that are bigger than the size of a packet.
	// See also SV_UpdateConfigStrings
	// bcs0 starts a new big config string
	// bcs1 continues it
	// bcs2 finishes it and feeds it back as a new command sent by the server (bcs0 makes it a cs command)
	if (cmd == "bcs0") {
		if (argc >= 3) {
			Com_sprintf(bigConfigString, BIG_INFO_STRING, "cs %s %s", args.Argv(1).c_str(), args.EscapedArgs(2).c_str());
		}
		return false;
	}

	if (cmd == "bcs1") {
		if (argc >= 3) {
			const char* s = Cmd_QuoteString( args[2].c_str() );

			if (strlen(bigConfigString) + strlen(s) >= BIG_INFO_STRING) {
				Com_Error(errorParm_t::ERR_DROP, "bcs exceeded BIG_INFO_STRING");
			}

			Q_strcat(bigConfigString, sizeof(bigConfigString), s);
		}
		return false;
	}

	if (cmd == "bcs2") {
		if (argc >= 3) {
			const char* s = Cmd_QuoteString( args[2].c_str() );

			if (strlen(bigConfigString) + strlen(s) + 1 >= BIG_INFO_STRING) {
				Com_Error(errorParm_t::ERR_DROP, "bcs exceeded BIG_INFO_STRING");
			}

			Q_strcat(bigConfigString, sizeof(bigConfigString), s);
			Q_strcat(bigConfigString, sizeof(bigConfigString), "\"");
			newText = bigConfigString;
			return CL_HandleServerCommand(bigConfigString, newText);
		}
		return false;
	}

	if (cmd == "cs") {
		CL_ConfigstringModified(args);
		return true;
	}

	if (cmd == "map_restart") {
		// clear outgoing commands before passing
		// the restart to the cgame
		memset(cl.cmds, 0, sizeof(cl.cmds));
		return true;
	}

	if (cmd == "popup") {
		// direct server to client popup request, bypassing cgame
		if (cls.state == connstate_t::CA_ACTIVE && !clc.demoplaying && argc >=1) {
			// TODO: Pass to the cgame
		}
		return false;
	}

	if (cmd == "pubkey_decrypt") {
		char         buffer[ MAX_STRING_CHARS ] = "pubkey_identify ";
		NettleLength msg_len = MAX_STRING_CHARS - 16;
		mpz_t        message;

		if (argc == 1) {
			Log::Notice("^3Server sent a pubkey_decrypt command, but sent nothing to decrypt!\n");
			return false;
		}

		mpz_init_set_str(message, args.Argv(1).c_str(), 16);

		if (rsa_decrypt(&private_key, &msg_len, (unsigned char *) buffer + 16, message)) {
			nettle_mpz_set_str_256_u(message, msg_len, (unsigned char *) buffer + 16);
			mpz_get_str(buffer + 16, 16, message);
			CL_AddReliableCommand(buffer);
		}

		mpz_clear(message);
		return false;
	}

	return true;
}