|
|
//===== Copyright � 1996-2009, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#include "mm_framework.h"
#include "fmtstr.h"
#include "vstdlib/random.h"
#include "protocol.h"
#include "proto_oob.h"
#include "bitbuf.h"
#include "checksum_crc.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
ConVar mm_dedicated_allow( "mm_dedicated_allow", "1", FCVAR_DEVELOPMENTONLY, "1 = allow searches for dedicated servers" ); ConVar mm_dedicated_fake( "mm_dedicated_fake", "0", FCVAR_DEVELOPMENTONLY, "1 = pretend like search is going, but abort after some time" ); ConVar mm_dedicated_force_servers( "mm_dedicated_force_servers", "", FCVAR_RELEASE, "Comma delimited list of ip:port of servers used to search for dedicated servers instead of searching for public servers.\n" "Use syntax `publicip1:port|privateip1:port,publicip2:port|privateip2:port` if your server is behind NAT.\n" "If the server is behind NAT, you can specify `0.0.0.0|privateip:port` and if server port is in the list of `mm_server_search_lan_ports` its public address should be automatically detected." ); ConVar mm_dedicated_ip( "mm_dedicated_ip", "", FCVAR_DEVELOPMENTONLY, "IP address of dedicated servers to consider available" ); ConVar mm_dedicated_timeout_request( "mm_dedicated_timeout_request", "20", FCVAR_DEVELOPMENTONLY ); ConVar mm_dedicated_search_maxping( "mm_dedicated_search_maxping", IsX360() ? "200" : "150", FCVAR_RELEASE | FCVAR_ARCHIVE, "Longest preferred ping to dedicated servers for games", true, 25.f, true, 350.f ); ConVar mm_dedicated_search_maxresults( "mm_dedicated_search_maxresults", "75", FCVAR_DEVELOPMENTONLY );
extern ConVar mm_dedicated_xlsp_timeout;
CDsSearcher::CDsSearcher( KeyValues *pSettings, uint64 uiReserveCookie, IMatchSession *pMatchSession, uint64 ullCrypt ) : m_pSettings( pSettings ), m_uiReserveCookie( uiReserveCookie ), m_pReserveSettings( g_pMatchFramework->GetMatchNetworkMsgController()->PackageGameDetailsForReservation( m_pSettings ) ), m_autodelete_pReserveSettings( m_pReserveSettings ), #ifdef _X360
m_pTitleServers( NULL ), #elif !defined( NO_STEAM )
m_pServerListListener( NULL ), m_nSearchPass( 0 ), #endif
m_eState( STATE_INIT ), m_flTimeout( 0.0f ), m_pAsyncOperation( NULL ), m_pMatchSession( pMatchSession ), m_ullCrypt( ullCrypt ) { #ifdef _X360
ZeroMemory( m_chDatacenterQuery, sizeof( m_chDatacenterQuery ) ); ZeroMemory( &m_dc, sizeof( m_dc ) ); #endif
DevMsg( "Created DS searcher\n" ); KeyValuesDumpAsDevMsg( m_pSettings );
memset( &m_Result, 0, sizeof( m_Result ) );
// Build the reservation settings
// Load test
m_bLoadTest = (m_pSettings->GetInt( "options/sv_load_test", 0) == 1); }
CDsSearcher::~CDsSearcher() { ; }
void CDsSearcher::Update() { switch ( m_eState ) { case STATE_INIT: { char const *szNetwork = m_pSettings->GetString( "system/network", "" ); char const *szServer = m_pSettings->GetString( "options/server", "listen" ); if ( m_pSettings->GetString( "server/server", NULL ) ) { InitWithKnownServer(); } else if ( mm_dedicated_allow.GetBool() && !Q_stricmp( "LIVE", szNetwork ) && Q_stricmp( "listen", szServer ) && !( g_pMatchFramework->GetMatchTitle()->GetTitleSettingsFlags() & MATCHTITLE_SETTING_NODEDICATED ) ) { InitDedicatedSearch(); } else { m_eState = STATE_FINISHED; } } break;
case STATE_WAITING: { if ( Plat_FloatTime() > m_flTimeout ) m_eState = STATE_FINISHED; } break;
#ifdef _X360
case STATE_XLSP_ENUMERATE_DCS: m_pTitleServers->Update(); if ( m_pTitleServers->IsSearchCompleted() ) Xlsp_OnEnumerateDcsCompleted(); break;
case STATE_XLSP_NEXT_DC: Xlsp_StartNextDc(); break;
case STATE_XLSP_REQUESTING_SERVERS: if ( Plat_FloatTime() > m_flTimeout ) { DevWarning( "XLSP datacenter `%s` timed out.\n", m_dc.m_szGatewayName ); m_dc.Destroy(); m_eState = STATE_XLSP_NEXT_DC; } break;
#elif !defined( NO_STEAM )
case STATE_STEAM_REQUESTING_SERVERS: if ( Plat_FloatTime() > m_flTimeout ) { DevWarning( "Steam search for dedicated servers timed out.\n" ); Steam_OnDedicatedServerListFetched(); } break;
case STATE_STEAM_NEXT_SEARCH_PASS: Steam_SearchPass(); break;
#endif
} }
void CDsSearcher::OnEvent( KeyValues *pEvent ) { char const *szEvent = pEvent->GetName();
#ifdef _X360
if ( m_eState == STATE_XLSP_REQUESTING_SERVERS && !Q_stricmp( "M2A_SERVER_BATCH", szEvent ) ) { void const *pData = pEvent->GetPtr( "ptr" ); int numBytes = pEvent->GetInt( "size" );
Xlsp_OnDcServerBatch( pData, numBytes ); } #elif !defined( NO_STEAM )
szEvent; #endif
}
void CDsSearcher::Destroy() { if ( m_pAsyncOperation ) { m_pAsyncOperation->Release(); m_pAsyncOperation = NULL; }
#ifdef _X360
switch ( m_eState ) { case STATE_XLSP_ENUMERATE_DCS: if ( m_pTitleServers ) m_pTitleServers->Destroy(); m_pTitleServers = NULL; break; case STATE_XLSP_REQUESTING_SERVERS: case STATE_RESERVING: m_dc.Destroy(); break; } #elif !defined( NO_STEAM )
if ( m_pServerListListener ) { m_pServerListListener->Destroy(); m_pServerListListener = NULL; } #endif
delete this; }
bool CDsSearcher::IsFinished() { return m_eState == STATE_FINISHED; }
CDsSearcher::DsResult_t const & CDsSearcher::GetResult() { return m_Result; }
void CDsSearcher::DsResult_t::CopyToServerKey( KeyValues *pKvServer, uint64 ullCrypt ) const { Assert( m_bDedicated ); pKvServer->SetString( "server", "dedicated" );
#ifdef _X360
pKvServer->SetString( "adrInsecure", m_szInsecureSendableServerAddress ); #elif !defined( NO_STEAM )
if ( char const *szEncrypted = MatchSession_EncryptAddressString( m_szPublicConnectionString, ullCrypt ) ) pKvServer->SetString( "adronline", szEncrypted ); else pKvServer->SetString( "adronline", m_szPublicConnectionString ); if ( m_szPrivateConnectionString[0] ) { if ( char const *szEncrypted = MatchSession_EncryptAddressString( m_szPrivateConnectionString, ullCrypt ) ) pKvServer->SetString( "adrlocal", szEncrypted ); else pKvServer->SetString( "adrlocal", m_szPrivateConnectionString ); } #endif
}
//
// Implementation
//
void CDsSearcher::InitDedicatedSearch() { if ( mm_dedicated_fake.GetBool() ) { // Special fake of the search - it just spins for some time and
// pretends like it was aborted
m_flTimeout = Plat_FloatTime() + mm_dedicated_timeout_request.GetFloat(); m_eState = STATE_WAITING; m_Result.m_bAborted = true; return; }
#ifdef _X360
Xlsp_EnumerateDcs(); #elif !defined( NO_STEAM )
m_flTimeout = Plat_FloatTime() + mm_dedicated_timeout_request.GetFloat(); Steam_SearchPass(); #endif
}
void CDsSearcher::InitWithKnownServer() { #ifdef _X360
Assert( 0 ); m_eState = STATE_FINISHED; return; #elif !defined( NO_STEAM )
if ( m_pSettings->GetInt( "server/reserved" ) ) { m_Result.m_bDedicated = true; char const *szAdrOnline = m_pSettings->GetString( "server/adronline", "" ); if ( char const *szDecrypted = MatchSession_DecryptAddressString( szAdrOnline, m_ullCrypt ) ) szAdrOnline = szDecrypted; Q_strncpy( m_Result.m_szConnectionString, szAdrOnline, ARRAYSIZE( m_Result.m_szConnectionString ) ); Q_strncpy( m_Result.m_szPublicConnectionString, szAdrOnline, ARRAYSIZE( m_Result.m_szPublicConnectionString ) );
char const *szAdrLocal = m_pSettings->GetString( "server/adrlocal", "" ); if ( char const *szDecrypted = MatchSession_DecryptAddressString( szAdrLocal, m_ullCrypt ) ) szAdrLocal = szDecrypted; Q_strncpy( m_Result.m_szPrivateConnectionString, szAdrLocal, ARRAYSIZE( m_Result.m_szPrivateConnectionString ) );
m_eState = STATE_FINISHED; } else { DsServer_t dsResult( m_pSettings->GetString( "server/adronline", "" ), m_pSettings->GetString( "server/adrlocal", "" ), 0 ); if ( char const *szDecrypted = MatchSession_DecryptAddressString( dsResult.m_szConnectionString, m_ullCrypt ) ) Q_strncpy( dsResult.m_szConnectionString, szDecrypted, ARRAYSIZE( dsResult.m_szConnectionString ) ); if ( char const *szDecrypted = MatchSession_DecryptAddressString( dsResult.m_szPrivateConnectionString, m_ullCrypt ) ) Q_strncpy( dsResult.m_szPrivateConnectionString, szDecrypted, ARRAYSIZE( dsResult.m_szPrivateConnectionString ) );
m_arrServerList.AddToTail( dsResult );
ReserveNextServer(); } #endif
}
#ifdef _X360
void CDsSearcher::Xlsp_EnumerateDcs() { m_eState = STATE_XLSP_ENUMERATE_DCS; m_pTitleServers = new CXlspTitleServers( mm_dedicated_search_maxping.GetInt(), false ); }
void CDsSearcher::Xlsp_OnEnumerateDcsCompleted() { DevMsg( "Xlsp_OnEnumerateDcsCompleted - analyzing QOS results...\n" ); CUtlVector< CXlspDatacenter > &arrDcs = m_pTitleServers->GetDatacenters(); m_arrDatacenters.AddMultipleToTail( arrDcs.Count(), arrDcs.Base() ); m_pTitleServers->Destroy(); m_pTitleServers = NULL;
//
// Sort and randomize the accepted results
//
m_arrDatacenters.Sort( CXlspDatacenter::Compare ); for ( int k = 0; k < m_arrDatacenters.Count() - 1; ++ k ) { CXlspDatacenter &dc1 = m_arrDatacenters[ k ]; CXlspDatacenter &dc2 = m_arrDatacenters[ k + 1 ]; if ( dc1.m_nPingBucket == dc2.m_nPingBucket && RandomInt( 0, 1 ) ) { CXlspDatacenter dcSwap = dc1; dc1 = dc2; dc2 = dcSwap; } }
DevMsg( "Xlsp_OnEnumerateDcsCompleted - accepted %d datacenters.\n", m_arrDatacenters.Count() ); for ( int k = 0; k < m_arrDatacenters.Count(); ++ k ) { DevMsg( " %d. `%s`\n", k, m_arrDatacenters[k].m_szGatewayName ); }
// Prepare the datacenter query
Xlsp_PrepareDatacenterQuery();
// Go to the next datacenter
m_eState = STATE_XLSP_NEXT_DC; }
void CDsSearcher::Xlsp_PrepareDatacenterQuery() { // Compute CRC of primary user's gamertag
byte bSult = RandomInt( 5, 100 ); CRC32_t crc32 = 0; if ( IPlayerLocal * player = g_pPlayerManager->GetLocalPlayer( XBX_GetPrimaryUserId() ) ) { char const *szPlayerName = player->GetName(); crc32 = CRC32_ProcessSingleBuffer( szPlayerName, strlen( szPlayerName ) );
uint32 sult32 = bSult | ( bSult << 8 ) | ( bSult << 16 ) | ( bSult << 24 ); crc32 ^= sult32; } if ( !crc32 ) bSult = 0;
// Search key
static ConVarRef sv_search_key( "sv_search_key" ); char const *szPrivateKey = sv_search_key.IsValid() ? sv_search_key.GetString() : ""; if ( !*szPrivateKey ) szPrivateKey = "default";
//
// Build query
//
Q_snprintf( m_chDatacenterQuery, ARRAYSIZE( m_chDatacenterQuery ), "\\empty\\1" "\\private\\%s" "\\players\\%d" "\\slots\\%d" "\\perm\\%s" "\\acct\\%02x%08x", szPrivateKey, m_pSettings->GetInt( "members/numPlayers", 0 ), m_pSettings->GetInt( "members/numSlots", 0 ), m_pSettings->GetString( "system/access", "public" ), bSult, crc32 );
DevMsg( "Datacenters query: %s\n", m_chDatacenterQuery ); }
void CDsSearcher::Xlsp_StartNextDc() { if ( !m_arrDatacenters.Count() ) { m_eState = STATE_FINISHED; return; }
//
// Get the next datacenter off the list
//
m_dc = m_arrDatacenters.Head(); m_arrDatacenters.RemoveMultipleFromHead( 1 ); m_flTimeout = Plat_FloatTime() + mm_dedicated_xlsp_timeout.GetFloat();
DevMsg( "[XLSP] Requesting server batch from %s:%d (%d masters) - ping %d [<= %d]\n" " ProbesXmit=%3d ProbesRecv=%3d\n" " RttMinInMsecs=%3d RttMedInMsecs=%3d\n" " UpBitsPerSec=%6d DnBitsPerSec=%6d\n", m_dc.m_szGatewayName, m_dc.m_nMasterServerPortStart, m_dc.m_numMasterServers, m_dc.m_qos.wRttMedInMsecs, m_dc.m_nPingBucket, m_dc.m_qos.cProbesXmit, m_dc.m_qos.cProbesRecv, m_dc.m_qos.wRttMinInMsecs, m_dc.m_qos.wRttMedInMsecs, m_dc.m_qos.dwUpBitsPerSec, m_dc.m_qos.dwDnBitsPerSec );
if ( CommandLine()->FindParm( "-xlsp_fake_gateway" ) ) { m_dc.m_adrSecure = m_dc.m_xsi.inaServer; } else { //
// Resolve the secure address
//
DWORD ret = g_pMatchExtensions->GetIXOnline()->XNetServerToInAddr( m_dc.m_xsi.inaServer, g_pMatchFramework->GetMatchTitle()->GetTitleServiceID(), &m_dc.m_adrSecure ); if ( ret != ERROR_SUCCESS ) { DevWarning( "Failed to resolve XLSP secure address (code = 0x%08X)!\n", ret ); return; } }
// Convert to netadr_t on a random master port
netadr_t inetAddr; inetAddr.SetType( NA_IP ); inetAddr.SetIPAndPort( m_dc.m_adrSecure.s_addr, m_dc.m_nMasterServerPortStart + RandomInt( 0, m_dc.m_numMasterServers - 1 ) );
//
// Prepare the request payload
//
char msg_buffer[ INetSupport::NC_MAX_ROUTABLE_PAYLOAD ]; bf_write msg( msg_buffer, sizeof( msg_buffer ) );
msg.WriteByte( A2M_GET_SERVERS_BATCH2 ); msg.WriteByte( '\n' ); msg.WriteLong( 0 ); // batch starts at 0
msg.WriteLong( m_dc.m_adrSecure.s_addr ); // datacenter's challenge
msg.WriteString( m_chDatacenterQuery ); // datacenter query
msg.WriteByte( '\n' );
g_pMatchExtensions->GetINetSupport()->SendPacket( NULL, INetSupport::NS_SOCK_CLIENT, inetAddr, msg.GetData(), msg.GetNumBytesWritten() );
m_eState = STATE_XLSP_REQUESTING_SERVERS; }
void CDsSearcher::Xlsp_OnDcServerBatch( void const *pData, int numBytes ) { if ( numBytes < 8 ) return;
bf_read msg( pData, numBytes ); int nNextId = msg.ReadLong(); nNextId;
uint nChallenge = msg.ReadLong(); if ( nChallenge != m_dc.m_adrSecure.s_addr ) return;
//
// Get master server reply message or Secure Gateway name (must match request)
//
char szReply[ MAX_PATH ] = {0}; msg.ReadString( szReply, ARRAYSIZE( szReply ), true );
if ( !szReply[0] ) { DevWarning( "XLSP master server: empty response.\n" ); m_dc.Destroy(); m_eState = STATE_XLSP_NEXT_DC; return; }
if ( !Q_stricmp( "##full", szReply ) ) { DevWarning( "XLSP master server: full.\n" ); m_dc.Destroy(); m_eState = STATE_XLSP_NEXT_DC; return; }
if ( !Q_stricmp( "##local", szReply ) ) { DevWarning( "XLSP master server: game is not eligible for dedicated server.\n" ); m_dc.Destroy(); m_eState = STATE_FINISHED; return; }
// Bypass the gateway name check if we're faking it.
if ( !CommandLine()->FindParm( "-xlsp_fake_gateway" ) ) { if ( Q_stricmp( m_dc.m_szGatewayName, szReply ) ) { DevWarning( "XLSP master server: wrong reply `%s`, expected gateway `%s`.\n", szReply, m_dc.m_szGatewayName ); m_dc.Destroy(); m_eState = STATE_XLSP_NEXT_DC; return; } }
//
// Process all the servers in the batch
//
m_arrServerPorts.RemoveAll(); for ( ; ; ) { uint16 nPort = msg.ReadWord(); if ( !nPort || nPort == 0xFFFF ) { // end of list
break; }
m_arrServerPorts.AddToTail( nPort ); } DevWarning( "XLSP master server: returned %d servers in batch.\n", m_arrServerPorts.Count() );
// Go ahead and start reserving
ReserveNextServer(); }
#elif !defined( NO_STEAM )
void CDsSearcher::Steam_SearchPass() { if ( mm_dedicated_force_servers.GetString()[0] ) { // if convar is on to force dedicated server choices, pretend we got search results of just those servers
CSplitString serverList( mm_dedicated_force_servers.GetString(), "," );
for ( int i = 0; i < serverList.Count(); i++ ) { // Check if the specification has a private IP address
char const * adrsStrings[2] = { serverList[i], "" }; if ( char *pchDelim = strchr( serverList[i], '|' ) ) { *( pchDelim ++ ) = 0; adrsStrings[1] = pchDelim; }
netadr_t adrsForced[2]; adrsForced[0].SetFromString( adrsStrings[0] ); adrsForced[1].SetFromString( adrsStrings[1] );
// Check if a locally discovered server is known with
// either public or private address that is being forced
int numServers = g_pServerManager->GetNumServers(); for ( int iServer = 0; iServer < numServers; ++ iServer ) { IMatchServer *pMatchServer = g_pServerManager->GetServerByIndex( iServer ); if ( !pMatchServer ) continue;
KeyValues *pServerDetails = pMatchServer->GetGameDetails(); netadr_t adrsKnown[2]; char const * adrsStringsKnown[2] = { pServerDetails->GetString( "server/adronline" ), pServerDetails->GetString( "server/adrlocal" ) }; adrsKnown[0].SetFromString( adrsStringsKnown[0] ); adrsKnown[1].SetFromString( adrsStringsKnown[1] );
for ( int iAdrForced = 0; iAdrForced < ARRAYSIZE( adrsForced ); ++ iAdrForced ) { for ( int iAdrKnown = 0; iAdrKnown < ARRAYSIZE( adrsKnown ); ++ iAdrKnown ) { if ( adrsForced[iAdrForced].GetIPHostByteOrder() && adrsKnown[iAdrKnown].GetIPHostByteOrder() && adrsForced[iAdrForced].CompareAdr( adrsKnown[iAdrKnown] ) ) { if ( !adrsForced[!iAdrForced].GetIPHostByteOrder() ) // user not forcing other address, but we know it
adrsStrings[!iAdrForced] = adrsStringsKnown[!iAdrKnown]; goto finished_server_lookup; } } } } finished_server_lookup:
m_arrServerList.AddToTail( CDsSearcher::DsServer_t( adrsStrings[0], adrsStrings[1], 0 ) ); // you get no accurate ping to forced servers
}
Steam_OnDedicatedServerListFetched(); return; }
CUtlVector< MatchMakingKeyValuePair_t > filters; filters.EnsureCapacity( 10 );
// filter by game and require empty server
filters.AddToTail( MatchMakingKeyValuePair_t( "gamedir", COM_GetModDirectory() ) ); filters.AddToTail( MatchMakingKeyValuePair_t( "noplayers", "1" ) );
// Official servers
bool bNeedOfficialServer = false; char const *szServerType = m_pSettings->GetString( "options/server", NULL ); if ( szServerType && !Q_stricmp( szServerType, "official" ) ) { bNeedOfficialServer = true; filters.AddToTail( MatchMakingKeyValuePair_t( "white", "1" ) ); }
// Allow the game to extend the filters
if ( KeyValues *pExtra = g_pMMF->GetMatchTitleGameSettingsMgr()->DefineDedicatedSearchKeys( m_pSettings, bNeedOfficialServer, m_nSearchPass ) ) { if ( !mm_dedicated_ip.GetString()[0] ) { for ( KeyValues *val = pExtra->GetFirstValue(); val; val = val->GetNextValue() ) { char const *szValue = val->GetString(); if ( !szValue || !*szValue ) continue; filters.AddToTail( MatchMakingKeyValuePair_t( val->GetName(), szValue ) ); } } pExtra->deleteThis(); }
// Load test
if (m_bLoadTest && m_nSearchPass == 0) { // Add to the "gametype" filter
for ( int i=0; i < filters.Count(); i++ ) { MatchMakingKeyValuePair_t *pKV = &(filters[i]); if ( !Q_stricmp( pKV->m_szKey, "gametype" ) ) { Q_strncat( pKV->m_szValue, ",sv_load_test", sizeof(pKV->m_szValue) ); break; } } }
// request the server list. We will get called back at ServerResponded, ServerFailedToRespond, and RefreshComplete
m_eState = STATE_STEAM_REQUESTING_SERVERS; m_pServerListListener = new CServerListListener( this, filters ); ++m_nSearchPass; }
CDsSearcher::CServerListListener::CServerListListener( CDsSearcher *pDsSearcher, CUtlVector< MatchMakingKeyValuePair_t > &filters ) : m_pOuter( pDsSearcher ), m_hRequest( NULL ) { MatchMakingKeyValuePair_t *pFilter = filters.Base(); DevMsg( 1, "Requesting dedicated server list...\n" ); for (int i = 0; i < filters.Count(); i++) { DevMsg("Filter %d: %s=%s\n", i, filters.Element(i).m_szKey, filters.Element(i).m_szValue); } m_hRequest = steamapicontext->SteamMatchmakingServers()->RequestInternetServerList( ( AppId_t ) g_pMatchFramework->GetMatchTitle()->GetTitleID(), &pFilter, filters.Count(), this ); }
void CDsSearcher::CServerListListener::Destroy() { m_pOuter = NULL; if ( m_hRequest ) steamapicontext->SteamMatchmakingServers()->ReleaseRequest( m_hRequest ); m_hRequest = NULL;
delete this; }
void CDsSearcher::CServerListListener::ServerResponded( HServerListRequest hReq, int iServer ) { gameserveritem_t *pServer = steamapicontext->SteamMatchmakingServers() ->GetServerDetails( hReq, iServer );
Msg( "[MM] Server responded '%s', dist %d\n", pServer->m_NetAdr.GetConnectionAddressString(), pServer->m_nPing );
// Check if the server IP address matches
char const *szDedicatedIp = mm_dedicated_ip.GetString(); if ( szDedicatedIp && szDedicatedIp[0] ) { char const *szServerConnString = pServer->m_NetAdr.GetConnectionAddressString(); szServerConnString = StringAfterPrefix( szServerConnString, szDedicatedIp ); if ( !szServerConnString || ( szServerConnString[0] && szServerConnString[0] != ':' ) ) { DevMsg( " rejected dedicated server '%s' due to ip filter '%s'\n", pServer->m_NetAdr.GetConnectionAddressString(), szDedicatedIp ); return; } }
// Register the dedicated server as acceptable
// netadr_t adrPublic, adrPrivate;
// adrPublic.SetFromString( pServer->m_NetAdr.GetConnectionAddressString() );
// TODO: bool bHasPrivate = FindLANServerPrivateIPByPublicIP( adrPublic, adrPrivate );
// Don't reserve servers with human players playing
int nHumanPlayers = pServer->m_nPlayers - pServer->m_nBotPlayers; if ( nHumanPlayers > 0 ) return;
// Don't reserve servers with too high ping
if ( ( mm_dedicated_search_maxping.GetInt() > 0 ) && ( pServer->m_nPing > mm_dedicated_search_maxping.GetInt() ) ) return;
// Register the result
if ( m_pOuter ) { // See if maybe we know about a private address for this server
char const *szPrivateAddress = ""; netadr_t adrPublic; adrPublic.SetFromString( pServer->m_NetAdr.GetConnectionAddressString() );
XUID xuidOnline = uint64( adrPublic.GetIPNetworkByteOrder() ) | ( uint64( adrPublic.GetPort() ) << 32ull ); if ( IMatchServer *pMatchServer = g_pServerManager->GetServerByOnlineId( xuidOnline ) ) { szPrivateAddress = pMatchServer->GetGameDetails()->GetString( "server/adrlocal" ); }
m_pOuter->m_arrServerList.AddToTail( CDsSearcher::DsServer_t( pServer->m_NetAdr.GetConnectionAddressString(), szPrivateAddress, pServer->m_nPing ) );
if ( m_pOuter->m_arrServerList.Count() > mm_dedicated_search_maxresults.GetInt() || Plat_FloatTime() > m_pOuter->m_flTimeout ) { steamapicontext->SteamMatchmakingServers()->CancelQuery( hReq ); } } }
void CDsSearcher::CServerListListener::RefreshComplete( HServerListRequest hReq, EMatchMakingServerResponse response ) { if ( m_pOuter ) { m_pOuter->Steam_OnDedicatedServerListFetched(); } }
void CDsSearcher::Steam_OnDedicatedServerListFetched() { if ( m_bLoadTest && m_nSearchPass < 2 ) { m_eState = STATE_INIT; } else { if ( m_pServerListListener ) { m_pServerListListener->Destroy(); m_pServerListListener = NULL; }
DevMsg( 1, "Dedicated server list fetched %d servers.\n", m_arrServerList.Count() );
ReserveNextServer(); } }
#endif
void CDsSearcher::ReserveNextServer() { m_eState = STATE_RESERVING;
#ifdef _X360
if ( !m_arrServerPorts.Count() ) { m_dc.Destroy(); m_eState = STATE_XLSP_NEXT_DC; return; }
uint16 nPort = m_arrServerPorts.Head(); m_arrServerPorts.RemoveMultipleFromHead( 1 );
netadr_t inetAddrSecure; inetAddrSecure.SetType( NA_IP ); inetAddrSecure.SetIPAndPort( m_dc.m_adrSecure.s_addr, nPort );
netadr_t inetAddrInsecureSendable; inetAddrInsecureSendable.SetType( NA_IP ); inetAddrInsecureSendable.SetIPAndPort( m_dc.m_xsi.inaServer.s_addr, nPort );
Q_strncpy( m_Result.m_szConnectionString, inetAddrSecure.ToString(), ARRAYSIZE( m_Result.m_szConnectionString ) ); Q_strncpy( m_Result.m_szInsecureSendableServerAddress, inetAddrInsecureSendable.ToString(), ARRAYSIZE( m_Result.m_szInsecureSendableServerAddress ) );
netadr_t addrPublic, addrPrivate; addrPrivate.SetType( NA_NULL ); addrPublic = inetAddrSecure;
#elif !defined( NO_STEAM )
if ( !m_arrServerList.Count() ) { if ( Plat_FloatTime() < m_flTimeout ) { m_eState = STATE_STEAM_NEXT_SEARCH_PASS; return; } else { m_eState = STATE_FINISHED; return; } }
DsServer_t dss = m_arrServerList.Head(); m_arrServerList.RemoveMultipleFromHead( 1 );
Q_strncpy( m_Result.m_szPublicConnectionString, dss.m_szConnectionString, ARRAYSIZE( m_Result.m_szPublicConnectionString ) ); Q_strncpy( m_Result.m_szPrivateConnectionString, dss.m_szPrivateConnectionString, ARRAYSIZE( m_Result.m_szPrivateConnectionString ) );
netadr_t addrPublic, addrPrivate; addrPublic.SetFromString( dss.m_szConnectionString ); if ( dss.m_szPrivateConnectionString[0] ) addrPrivate.SetFromString( dss.m_szPrivateConnectionString ); else addrPrivate.SetType( NA_NULL );
#else
netadr_t addrPublic, addrPrivate; #endif
g_pMatchExtensions->GetINetSupport()->ReserveServer( addrPublic, addrPrivate, m_uiReserveCookie, m_pReserveSettings, this, &m_pAsyncOperation ); }
void CDsSearcher::OnOperationFinished( IMatchAsyncOperation *pOperation ) { Assert( pOperation == m_pAsyncOperation ); uint64 uiResult = m_pAsyncOperation->GetResult(); if ( m_pAsyncOperation->GetState() == AOS_FAILED || !uiResult ) { ReserveNextServer(); } else { m_Result.m_bDedicated = true; char const *szReservedAddr = ( char const * )( int )uiResult; Q_strncpy( m_Result.m_szConnectionString, szReservedAddr, ARRAYSIZE( m_Result.m_szConnectionString ) );
// If this server reservation reported number of game slots then
// force that setting into session data
uint32 numGameSlots = uint32( pOperation->GetResultExtraInfo() & 0xFF ); if ( m_pMatchSession && ( numGameSlots > 0 ) ) { KeyValues *kvUpdate = new KeyValues( "update" ); KeyValues::AutoDelete autodelete( kvUpdate ); kvUpdate->SetInt( "update/members/numSlots", numGameSlots );
m_pMatchSession->UpdateSessionSettings( kvUpdate ); } m_eState = STATE_FINISHED; } }
|