예제 #1
0
/*
* SVC_SendInfoString
*/
static void SVC_SendInfoString( const socket_t *socket, const netadr_t *address, const char *requestType, const char *responseType, qboolean fullStatus )
{
	char *string;

	if( sv_showInfoQueries->integer )
		Com_Printf( "%s Packet %s\n", requestType, NET_AddressToString( address ) );

	// KoFFiE: When not public and coming from a LAN address
	//         assume broadcast and respond anyway, otherwise ignore
	if( ( ( !sv_public->integer ) && ( !NET_IsLANAddress( address ) ) ) ||
		( sv_maxclients->integer == 1 ) )
	{
		return;
	}

	// ignore when in invalid server state
	if( sv.state < ss_loading || sv.state > ss_game )
		return;

	// don't reply when we are locked for mm
	// if( SV_MM_IsLocked() )
	//	return;

	// send the same string that we would give for a status OOB command
	string = SV_LongInfoString( fullStatus );
	if( string )
		Netchan_OutOfBandPrint( socket, address, "%s\n\\challenge\\%s%s", responseType, Cmd_Argv( 1 ), string );
}
예제 #2
0
/*
* CL_ParseStatusMessage
* Handle a reply from a ping
*/
void CL_ParseStatusMessage( const socket_t *socket, const netadr_t *address, msg_t *msg )
{
	char *s = MSG_ReadString( msg );
	serverlist_t *pingserver;
	char adrString[64];

	Com_DPrintf( "%s\n", s );

	Q_strncpyz( adrString, NET_AddressToString( address ), sizeof( adrString ) );

	// ping response
	pingserver = CL_ServerFindInList( masterList, adrString );
	if( !pingserver )
		pingserver = CL_ServerFindInList( favoritesList, adrString );

	if( pingserver && pingserver->pingTimeStamp ) // valid ping
	{
		unsigned int ping = Sys_Milliseconds() - pingserver->pingTimeStamp;
		CL_UIModule_AddToServerList( adrString, va( "\\\\ping\\\\%i%s", ping, s ) );
		pingserver->pingTimeStamp = 0;
		pingserver->lastValidPing = Com_DaysSince1900();
		return;
	}

	// assume LAN response
	if( NET_IsLANAddress( address ) && ( localQueryTimeStamp + LAN_SERVER_PINGING_TIMEOUT > Sys_Milliseconds() ) ) {
		unsigned int ping = Sys_Milliseconds() - localQueryTimeStamp;
		CL_UIModule_AddToServerList( adrString, va( "\\\\ping\\\\%i%s", ping, s ) );
		return;
	}

	// add the server info, but ignore the ping, cause it's not valid
	CL_UIModule_AddToServerList( adrString, s );
}
예제 #3
0
/*
* TV_Downstream_SendInfoString
*/
static void TV_Downstream_SendInfoString( const socket_t *socket, const netadr_t *address, const char *responseType, bool fullStatus )
{
	char *string;

	// KoFFiE: When not public and coming from a LAN address
	//         assume broadcast and respond anyway, otherwise ignore
	if( ( ( !tv_public->integer ) && ( !NET_IsLANAddress( address ) ) ) ||
		( tv_maxclients->integer == 1 ) )
		return;

	// send the same string that we would give for a status OOB command
	string = TV_Downstream_LongInfoString( fullStatus );
	if( string )
		Netchan_OutOfBandPrint( socket, address, "%s\n\\challenge\\%s%s", responseType, Cmd_Argv( 1 ), string );
}
예제 #4
0
/*
* TV_Downstream_InfoResponse
* 
* Responds with short info for broadcast scans
* The second parameter should be the current protocol version number.
*/
static void TV_Downstream_InfoResponse( const socket_t *socket, const netadr_t *address )
{
	int i, count;
	char *string;
	bool allow_empty = false, allow_full = false;

	// KoFFiE: When not public and coming from a LAN address
	//         assume broadcast and respond anyway, otherwise ignore
	if( ( ( !tv_public->integer ) && ( !NET_IsLANAddress( address ) ) ) ||
		( tv_maxclients->integer == 1 ) )
		return;

	// different protocol version
	if( atoi( Cmd_Argv( 1 ) ) != APP_PROTOCOL_VERSION )
		return;

	// check for full/empty filtered states
	for( i = 0; i < Cmd_Argc(); i++ )
	{
		if( !Q_stricmp( Cmd_Argv( i ), "full" ) )
			allow_full = true;
		if( !Q_stricmp( Cmd_Argv( i ), "empty" ) )
			allow_empty = true;
	}

	count = 0;
	for( i = 0; i < tv_maxclients->integer; i++ )
		if( tvs.clients[i].state >= CS_CONNECTED )
			count++;

	if( ( count == tv_maxclients->integer ) && !allow_full )
		return;
	if( ( count == 0 ) && !allow_empty )
		return;

	string = TV_Downstream_ShortInfoString();
	if( string )
		Netchan_OutOfBandPrint( socket, address, "info\n%s", string );
}
예제 #5
0
/*
* SVC_InfoResponse
* 
* Responds with short info for broadcast scans
* The second parameter should be the current protocol version number.
*/
static void SVC_InfoResponse( const socket_t *socket, const netadr_t *address )
{
	int i, count;
	char *string;
	qboolean allow_empty = qfalse, allow_full = qfalse;

	if( sv_showInfoQueries->integer )
		Com_Printf( "Info Packet %s\n", NET_AddressToString( address ) );

	// KoFFiE: When not public and coming from a LAN address
	//         assume broadcast and respond anyway, otherwise ignore
	if( ( ( !sv_public->integer ) && ( !NET_IsLANAddress( address ) ) ) ||
		( sv_maxclients->integer == 1 ) )
	{
		return;
	}

	// ignore when in invalid server state
	if( sv.state < ss_loading || sv.state > ss_game )
		return;

	// don't reply when we are locked for mm
	// if( SV_MM_IsLocked() )
	//	return;

	// different protocol version
	if( atoi( Cmd_Argv( 1 ) ) != APP_PROTOCOL_VERSION )
		return;

	// check for full/empty filtered states
	for( i = 0; i < Cmd_Argc(); i++ )
	{
		if( !Q_stricmp( Cmd_Argv( i ), "full" ) )
			allow_full = qtrue;

		if( !Q_stricmp( Cmd_Argv( i ), "empty" ) )
			allow_empty = qtrue;
	}

	count = 0;
	for( i = 0; i < sv_maxclients->integer; i++ )
	{
		if( svs.clients[i].state >= CS_CONNECTED )
		{
			count++;
		}
	}

	if( ( count == sv_maxclients->integer ) && !allow_full )
	{
		return;
	}

	if( ( count == 0 ) && !allow_empty )
	{
		return;
	}

	string = SV_ShortInfoString();
	if( string )
		Netchan_OutOfBandPrint( socket, address, "info\n%s", string );
}
예제 #6
0
파일: sv_oob.c 프로젝트: futurepneu/racemod
/**
 * Responds to a Steam server query.
 *
 * @param s       query string
 * @param socket  response socket
 * @param address response address
 * @param inmsg   message for arguments
 * @return whether the request was handled as a Steam query
 */
bool SV_SteamServerQuery( const char *s, const socket_t *socket, const netadr_t *address, msg_t *inmsg )
{
#if APP_STEAMID
	if( sv.state < ss_loading || sv.state > ss_game )
		return false; // server not running

	if( ( !sv_public->integer && !NET_IsLANAddress( address ) ) || ( sv_maxclients->integer == 1 ) )
		return false;

	if( !strcmp( s, "i" ) )
	{
		// ping
		const char pingResponse[] = "j00000000000000";
		Netchan_OutOfBand( socket, address, sizeof( pingResponse ), ( const uint8_t * )pingResponse );
		return true;
	}

	if( !strcmp( s, "W" ) || !strcmp( s, "U\xFF\xFF\xFF\xFF" ) )
	{
		// challenge - security feature, but since we don't send multiple packets always return 0
		const uint8_t challengeResponse[] = { 'A', 0, 0, 0, 0 };
		Netchan_OutOfBand( socket, address, sizeof( challengeResponse ), ( const uint8_t * )challengeResponse );
		return true;
	}

	if( !strcmp( s, "TSource Engine Query" ) )
	{
		// server info
		char hostname[MAX_INFO_VALUE];
		char gamedir[MAX_QPATH];
		char gamename[128];
		char version[32];
		char tags[MAX_STEAMQUERY_TAG_STRING];
		int i, players = 0, bots = 0, maxclients = 0;
		int flags = 0x80 | 0x01; // game port | game ID containing app ID
		client_t *cl;
		msg_t msg;
		uint8_t msgbuf[MAX_STEAMQUERY_PACKETLEN - sizeof( int32_t )];

		if( sv_showInfoQueries->integer )
			Com_Printf( "Steam Info Packet %s\n", NET_AddressToString( address ) );

		Q_strncpyz( hostname, COM_RemoveColorTokens( sv_hostname->string ), sizeof( hostname ) );
		if( !hostname[0] )
			Q_strncpyz( hostname, sv_hostname->dvalue, sizeof( hostname ) );
		Q_strncpyz( gamedir, FS_GameDirectory(), sizeof( gamedir ) );

		Q_strncpyz( gamename, APPLICATION, sizeof( gamename ) );
		if( Cvar_Value( "g_instagib" ) )
			Q_strncatz( gamename, " IG", sizeof( gamename ) );
		if( sv.configstrings[CS_GAMETYPETITLE][0] || sv.configstrings[CS_GAMETYPENAME][0] )
		{
			Q_strncatz( gamename, " ", sizeof( gamename ) );
			Q_strncatz( gamename,
				sv.configstrings[sv.configstrings[CS_GAMETYPETITLE][0] ? CS_GAMETYPETITLE : CS_GAMETYPENAME],
				sizeof( gamename ) );
		}

		for( i = 0; i < sv_maxclients->integer; i++ )
		{
			cl = &svs.clients[i];
			if( cl->state >= CS_CONNECTED )
			{
				if( cl->tvclient ) // exclude TV from the max players count
					continue;
				if( cl->edict->r.svflags & SVF_FAKECLIENT )
					bots++;
				players++;
			}
			maxclients++;
		}

		Q_snprintfz( version, sizeof( version ), "%i.%i.0.0", APP_VERSION_MAJOR, APP_VERSION_MINOR );

		SV_GetSteamTags( tags );
		if( tags[0] )
			flags |= 0x20;

		MSG_Init( &msg, msgbuf, sizeof( msgbuf ) );
		MSG_WriteByte( &msg, 'I' );
		MSG_WriteByte( &msg, APP_PROTOCOL_VERSION );
		MSG_WriteString( &msg, hostname );
		MSG_WriteString( &msg, sv.mapname );
		MSG_WriteString( &msg, gamedir );
		MSG_WriteString( &msg, gamename );
		MSG_WriteShort( &msg, 0 ); // app ID specified later
		MSG_WriteByte( &msg, min( players, 99 ) );
		MSG_WriteByte( &msg, min( maxclients, 99 ) );
		MSG_WriteByte( &msg, min( bots, 99 ) );
		MSG_WriteByte( &msg, ( dedicated && dedicated->integer ) ? 'd' : 'l' );
		MSG_WriteByte( &msg, STEAMQUERY_OS );
		MSG_WriteByte( &msg, Cvar_String( "password" )[0] ? 1 : 0 );
		MSG_WriteByte( &msg, 0 ); // VAC insecure
		MSG_WriteString( &msg, version );
		MSG_WriteByte( &msg, flags );
		// port
		MSG_WriteShort( &msg, sv_port->integer );
		// tags
		if( flags & 0x20 )
			MSG_WriteString( &msg, tags );
		// 64-bit game ID - needed to specify app ID
		MSG_WriteLong( &msg, APP_STEAMID & 0xffffff );
		MSG_WriteLong( &msg, 0 );
		Netchan_OutOfBand( socket, address, msg.cursize, msg.data );
		return true;
	}

	if( s[0] == 'U' )
	{
		// players
		msg_t msg;
		uint8_t msgbuf[MAX_STEAMQUERY_PACKETLEN - sizeof( int32_t )];
		int i, players = 0;
		client_t *cl;
		char name[MAX_NAME_BYTES];
		unsigned int time = Sys_Milliseconds();

		if( sv_showInfoQueries->integer )
			Com_Printf( "Steam Players Packet %s\n", NET_AddressToString( address ) );

		MSG_Init( &msg, msgbuf, sizeof( msgbuf ) );
		MSG_WriteByte( &msg, 'D' );
		MSG_WriteByte( &msg, 0 );

		for( i = 0; i < sv_maxclients->integer; i++ )
		{
			cl = &svs.clients[i];
			if( ( cl->state < CS_CONNECTED ) || cl->tvclient )
				continue;

			Q_strncpyz( name, COM_RemoveColorTokens( cl->name ), sizeof( name ) );
			if( ( msg.cursize + 10 + strlen( name ) ) > sizeof( msgbuf ) )
				break;

			MSG_WriteByte( &msg, i );
			MSG_WriteString( &msg, name );
			MSG_WriteLong( &msg, cl->edict->r.client->r.frags );
			MSG_WriteFloat( &msg, ( float )( time - cl->lastconnect ) * 0.001f );

			players++;
			if( players == 99 )
				break;
		}

		msgbuf[1] = players;
		Netchan_OutOfBand( socket, address, msg.cursize, msg.data );
		return true;
	}

	if( !strcmp( s, "s" ) )
	{
		// master server query, terminated by \n, followed by the challenge
		int i;
		bool fromMaster = false;
		int challenge;
		char gamedir[MAX_QPATH], basedir[MAX_QPATH], tags[MAX_STEAMQUERY_TAG_STRING];
		int players = 0, bots = 0, maxclients = 0;
		client_t *cl;
		char msg[MAX_STEAMQUERY_PACKETLEN];

		for( i = 0; i < MAX_MASTERS; i++ )
		{
			if( sv_masters[i].steam && NET_CompareAddress( address, &sv_masters[i].address ) )
			{
				fromMaster = true;
				break;
			}
		}
		if( !fromMaster )
			return true;

		if( sv_showInfoQueries->integer )
			Com_Printf( "Steam Master Server Info Packet %s\n", NET_AddressToString( address ) );

		challenge = MSG_ReadLong( inmsg );

		Q_strncpyz( gamedir, FS_GameDirectory(), sizeof( gamedir ) );
		Q_strncpyz( basedir, FS_BaseGameDirectory(), sizeof( basedir ) );
		SV_GetSteamTags( tags );

		for( i = 0; i < sv_maxclients->integer; i++ )
		{
			cl = &svs.clients[i];
			if( cl->state >= CS_CONNECTED )
			{
				if( cl->tvclient ) // exclude TV from the max players count
					continue;
				if( cl->edict->r.svflags & SVF_FAKECLIENT )
					bots++;
				players++;
			}
			maxclients++;
		}

		Q_snprintfz( msg, sizeof( msg ),
			"0\n\\protocol\\7\\challenge\\%i" // protocol must be 7 to match Source
			"\\players\\%i\\max\\%i\\bots\\%i"
			"\\gamedir\\%s\\map\\%s"
			"\\password\\%i\\os\\%c"
			"\\lan\\%i\\region\\255"
			"%s%s"
			"\\type\\%c\\secure\\0"
			"\\version\\%i.%i.0.0"
			"\\product\\%s\n",
			challenge,
			min( players, 99 ), min( maxclients, 99 ), min( bots, 99 ),
			gamedir, sv.mapname,
			Cvar_String( "password" )[0] ? 1 : 0, STEAMQUERY_OS,
			sv_public->integer ? 0 : 1,
			tags[0] ? "\\gametype\\" /* legacy - "gametype", not "tags" */ : "", tags,
			( dedicated && dedicated->integer ) ? 'd' : 'l',
			APP_VERSION_MAJOR, APP_VERSION_MINOR,
			basedir );
		NET_SendPacket( socket, ( const uint8_t * )msg, strlen( msg ), address );

		return true;
	}

	if( s[0] == 'O' )
	{
		// out of date message
		static bool printed = false;
		if( !printed )
		{
			int i;
			for( i = 0; i < MAX_MASTERS; i++ )
			{
				if( sv_masters[i].steam && NET_CompareAddress( address, &sv_masters[i].address ) )
				{
					Com_Printf( "Server is out of date and cannot be added to the Steam master servers.\n" );
					printed = true;
					return true;
				}
			}
		}
		return true;
	}
#endif

	return false;
}
예제 #7
0
파일: sv_main.c 프로젝트: hettoo/racesow
/*
* SV_UserinfoChanged
* 
* Pull specific info from a newly changed userinfo string
* into a more C friendly form.
*/
void SV_UserinfoChanged( client_t *client )
{
	char *val;
	int ival;

	assert( client );
	assert( Info_Validate( client->userinfo ) );

	if( !client->edict || !( client->edict->r.svflags & SVF_FAKECLIENT ) )
	{
		// force the IP key/value pair so the game can filter based on ip
		if( !Info_SetValueForKey( client->userinfo, "socket", NET_SocketTypeToString( client->netchan.socket->type ) ) )
		{
			SV_DropClient( client, DROP_TYPE_GENERAL, "Error: Couldn't set userinfo (socket)\n" );
			return;
		}
		if( !Info_SetValueForKey( client->userinfo, "ip", NET_AddressToString( &client->netchan.remoteAddress ) ) )
		{
			SV_DropClient( client, DROP_TYPE_GENERAL, "Error: Couldn't set userinfo (ip)\n" );
			return;
		}
	}

	// mm session
	ival = 0;
	val = Info_ValueForKey( client->userinfo, "cl_mm_session" );
	if( val )
		ival = atoi( val );
	if( !val || ival != client->mm_session )
		Info_SetValueForKey( client->userinfo, "cl_mm_session", va("%d", client->mm_session ) );

	// mm login
	if( client->mm_login[0] != '\0' ) {
		Info_SetValueForKey( client->userinfo, "cl_mm_login", client->mm_login );
	}
	else {
		Info_RemoveKey( client->userinfo, "cl_mm_login" );
	}

	// call prog code to allow overrides
	ge->ClientUserinfoChanged( client->edict, client->userinfo );

	if( !Info_Validate( client->userinfo ) )
	{
		SV_DropClient( client, DROP_TYPE_GENERAL, "Error: Invalid userinfo (after game)" );
		return;
	}

	// we assume that game module deals with setting a correct name
	val = Info_ValueForKey( client->userinfo, "name" );
	if( !val || !val[0] )
	{
		SV_DropClient( client, DROP_TYPE_GENERAL, "Error: No name set" );
		return;
	}
	Q_strncpyz( client->name, val, sizeof( client->name ) );

#ifndef RATEKILLED
	// rate command
	if( NET_IsLANAddress( &client->netchan.remoteAddress ) )
	{
		client->rate = 99999; // lans should not rate limit
	}
	else
	{
		val = Info_ValueForKey( client->userinfo, "rate" );
		if( val && val[0] )
		{
			int newrate;

			newrate = atoi( val );
			if( sv_maxrate->integer && newrate > sv_maxrate->integer )
				newrate = sv_maxrate->integer;
			else if( newrate > 90000 )
				newrate = 90000;
			if( newrate < 1000 )
				newrate = 1000;
			if( client->rate != newrate )
			{
				client->rate = newrate;
				Com_Printf( "%s%s has rate %i\n", client->name, S_COLOR_WHITE, client->rate );
			}
		}
		else
			client->rate = 5000;
	}
#endif
}
예제 #8
0
/**
 * Responds to a Steam server query.
 *
 * @param s       query string
 * @param socket  response socket
 * @param address response address
 * @param inmsg   message for arguments
 * @return whether the request was handled as a Steam query
 */
bool TV_Downstream_SteamServerQuery( const char *s, const socket_t *socket, const netadr_t *address, msg_t *inmsg )
{
#if APP_STEAMID
	if( ( !tv_public->integer && !NET_IsLANAddress( address ) ) || ( tv_maxclients->integer == 1 ) )
		return false;

	if( !strcmp( s, "i" ) )
	{
		// ping
		const char pingResponse[] = "j00000000000000";
		Netchan_OutOfBand( socket, address, sizeof( pingResponse ), ( const uint8_t * )pingResponse );
		return true;
	}

	if( !strcmp( s, "TSource Engine Query" ) )
	{
		// server info
		char hostname[MAX_INFO_VALUE];
		char gamedir[MAX_QPATH];
		char version[32];
		int i, count = 0;
		msg_t msg;
		uint8_t msgbuf[MAX_STEAMQUERY_PACKETLEN - sizeof( int32_t )];

		Q_strncpyz( hostname, COM_RemoveColorTokens( tv_name->string ), sizeof( hostname ) );
		if( !hostname[0] )
			Q_strncpyz( hostname, tv_name->dvalue, sizeof( hostname ) );
		Q_strncpyz( gamedir, FS_GameDirectory(), sizeof( gamedir ) );

		for( i = 0; i < tv_maxclients->integer; i++ )
		{
			if( tvs.clients[i].state >= CS_CONNECTED )
			{
				count++;
				if( count == 99 )
					break;
			}
		}

		Q_snprintfz( version, sizeof( version ), "%i.%i.0.0", APP_VERSION_MAJOR, APP_VERSION_MINOR );

		MSG_Init( &msg, msgbuf, sizeof( msgbuf ) );
		MSG_WriteByte( &msg, 'I' );
		MSG_WriteByte( &msg, APP_PROTOCOL_VERSION );
		MSG_WriteString( &msg, hostname );
		MSG_WriteString( &msg, "" ); // no map
		MSG_WriteString( &msg, gamedir );
		MSG_WriteString( &msg, APPLICATION " TV" );
		MSG_WriteShort( &msg, 0 ); // app ID specified later
		MSG_WriteByte( &msg, count );
		MSG_WriteByte( &msg, min( tv_maxclients->integer, 99 ) );
		MSG_WriteByte( &msg, 0 ); // no bots
		MSG_WriteByte( &msg, 'p' );
		MSG_WriteByte( &msg, STEAMQUERY_OS );
		MSG_WriteByte( &msg, tv_password->string[0] ? 1 : 0 );
		MSG_WriteByte( &msg, 0 ); // VAC insecure
		MSG_WriteString( &msg, version );
		MSG_WriteByte( &msg, 0x40 | 0x1 ); // spectator data | game ID containing app ID
		// spectator data
		MSG_WriteShort( &msg, tv_port->integer );
		MSG_WriteString( &msg, hostname );
		// 64-bit game ID - needed to specify app ID
		MSG_WriteLong( &msg, APP_STEAMID & 0xffffff );
		MSG_WriteLong( &msg, 0 );
		Netchan_OutOfBand( socket, address, msg.cursize, msg.data );
		return true;
	}

	if( !strcmp( s, "s" ) )
	{
		// master server query, terminated by \n, followed by the challenge
		bool isSteamMaster = false;
		int challenge;
		char gamedir[MAX_QPATH], basedir[MAX_QPATH];
		int i, count = 0;
		char msg[MAX_STEAMQUERY_PACKETLEN];

		if( !TV_Downstream_IsMaster( address, &isSteamMaster ) || !isSteamMaster )
			return true;

		challenge = MSG_ReadLong( inmsg );

		Q_strncpyz( gamedir, FS_GameDirectory(), sizeof( gamedir ) );
		Q_strncpyz( basedir, FS_BaseGameDirectory(), sizeof( basedir ) );

		for( i = 0; i < tv_maxclients->integer; i++ )
		{
			if( tvs.clients[i].state >= CS_CONNECTED )
			{
				count++;
				if( count == 99 )
					break;
			}
		}

		Q_snprintfz( msg, sizeof( msg ),
			"0\n\\protocol\\7\\challenge\\%i" // protocol must be 7 to match Source
			"\\players\\%i\\max\\%i\\bots\\0"
			"\\gamedir\\%s"
			"\\password\\%i\\os\\%c"
			"\\lan\\%i\\region\\255"
			"\\type\\p\\secure\\0"
			"\\version\\%i.%i.0.0"
			"\\product\\%s\n",
			challenge, 
			count, min( tv_maxclients->integer, 99 ),
			gamedir,
			tv_password->string[0] ? 1 : 0, STEAMQUERY_OS,
			tv_public->integer ? 0 : 1,
			APP_VERSION_MAJOR, APP_VERSION_MINOR,
			basedir );
		NET_SendPacket( socket, ( const uint8_t * )msg, strlen( msg ), address );

		return true;
	}

	if( s[0] == 'O' )
	{
		// out of date message
		static bool printed = false;
		if( !printed )
		{
			bool isSteamMaster = false;
			if( TV_Downstream_IsMaster( address, &isSteamMaster ) && isSteamMaster )
			{
				Com_Printf( "Server is out of date and cannot be added to the Steam master servers.\n" );
				printed = true;
			}
		}
		return true;
	}
#endif

	return false;
}