Counter Strike : Global Offensive Source Code
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
//====== Copyright c 1996-2007, Valve Corporation, All rights reserved. =======//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "matchmakingqos.h"
#include "threadtools.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#if defined( _X360 )
//-----------------------------------------------------------------------------
// Quality of Service detection routines
//-----------------------------------------------------------------------------
class CQosDetector { public: CQosDetector(); ~CQosDetector();
public: bool InitiateLookup(); bool WaitForResults();
public: MM_QOS_t GetResults() const { return m_Results; }
private: void Release(); XNQOS *m_pQos;
void ProcessResults(); MM_QOS_t m_Results; };
CQosDetector::CQosDetector() : m_pQos( NULL ) { m_Results.nPingMsMin = 50; // 50 ms default ping
m_Results.nPingMsMed = 50; // 50 ms default ping
m_Results.flBwUpKbs = 32.0f; // 32 KB/s = 256 kbps
m_Results.flBwDnKbs = 32.0f; // 32 KB/s = 256 kbps
m_Results.flLoss = 0.0f; // 0% packet loss
}
CQosDetector::~CQosDetector() { Release(); }
void CQosDetector::Release() { if ( m_pQos ) { g_pMatchExtensions->GetIXOnline()->XNetQosRelease( m_pQos ); m_pQos = NULL; } }
bool CQosDetector::InitiateLookup() { Release();
//
// Issue the asynchronous QOS service lookup query
//
XNQOS *pQos = NULL; INT err = g_pMatchExtensions->GetIXOnline()->XNetQosServiceLookup( NULL, NULL, &pQos ); if ( err ) { Msg( "CQosDetector::InitiateLookup failed, err = %d\n", err ); return false; } if ( !pQos ) { Msg( "CQosDetector::InitiateLookup failed, qos is null.\n" ); return false; } m_pQos = pQos; return true; }
bool CQosDetector::WaitForResults() { if ( !m_pQos ) return false;
//
// Spin-sleep here while waiting for the probes to come back
//
const int numSecQosTimeout = 30; // Consider QOS query timed out if 30 seconds elapsed
float flTimeStart = Plat_FloatTime(), flTimeEndTimeout = flTimeStart + numSecQosTimeout; for ( ; ; ) { if ( Plat_FloatTime() > flTimeEndTimeout ) { Msg( "CQosDetector::WaitForResults timed out after %d sec.\n", numSecQosTimeout ); Release(); return false; // Timed out
}
if ( m_pQos->axnqosinfo->bFlags & XNET_XNQOSINFO_COMPLETE ) break; // QOS query has completed
ThreadSleep( 10 ); }
if ( ! ( m_pQos->axnqosinfo->bFlags & XNET_XNQOSINFO_TARGET_CONTACTED ) || ( m_pQos->axnqosinfo->bFlags & XNET_XNQOSINFO_TARGET_DISABLED ) ) { // Failed to contact host or target disabled
Msg( "CQosDetector::WaitForResults host unavailable.\n" ); Release(); return false; }
ProcessResults(); Release(); return true; }
void CQosDetector::ProcessResults() { MM_QOS_t Results;
Results.nPingMsMin = m_pQos->axnqosinfo->wRttMinInMsecs; Results.nPingMsMed = m_pQos->axnqosinfo->wRttMedInMsecs;
Results.flBwUpKbs = m_pQos->axnqosinfo->dwUpBitsPerSec / 8192.0f; if ( Results.flBwUpKbs < 1.f ) { Results.flBwUpKbs = 1.f; } Results.flBwDnKbs = m_pQos->axnqosinfo->dwDnBitsPerSec / 8192.0f; if ( Results.flBwDnKbs < 1.f ) { Results.flBwDnKbs = 1.f; }
Results.flLoss = m_pQos->axnqosinfo->cProbesXmit ? ( float( m_pQos->axnqosinfo->cProbesXmit - m_pQos->axnqosinfo->cProbesRecv ) * 100.f / m_pQos->axnqosinfo->cProbesXmit ) : 0.f;
m_Results = Results;
// Dump the results
Msg( "[QOS] Fresh QOS results available:\n" "[QOS] ping %d min, %d med\n" "[QOS] bandwidth %.1f kB/s upstream, %.1f kB/s downstream\n" "[QOS] avg packet loss %.0f percents\n", Results.nPingMsMin, Results.nPingMsMed, Results.flBwUpKbs, Results.flBwDnKbs, Results.flLoss ); }
//
// Global QOS detector thread
//
static class CQosThread { public: CQosThread(); MM_QOS_t GetResults();
static unsigned ThreadProc( void *pThis ) { return ( (CQosThread *) pThis )->Run(), 0; } void Run(); private: ThreadHandle_t m_hHandle; CThreadEvent m_hRequestResultsEvent; // Auto reset event to trigger next query
CQosDetector m_QosDetector; } s_QosThread;
CQosThread::CQosThread() : m_hHandle( NULL ) { }
void CQosThread::Run() { //
// Sit here and fetch fresh QOS results whenever somebody needs them.
// Every request of QOS data is instantaneous and returns the last successful QOS query result.
//
for ( unsigned int numQosRequestsMade = 0; ; ++ numQosRequestsMade ) { m_QosDetector.InitiateLookup(); m_QosDetector.WaitForResults();
if ( numQosRequestsMade ) { m_hRequestResultsEvent.Wait(); } }
ReleaseThreadHandle( m_hHandle ); m_hHandle = NULL; }
MM_QOS_t CQosThread::GetResults() { // Launch the thread if this is the first time QOS is needed
if ( !m_hHandle ) { m_hHandle = CreateSimpleThread( ThreadProc, this ); if( m_hHandle ) { ThreadSetAffinity( m_hHandle, XBOX_PROCESSOR_3 ); } }
// Signal the event that we can make a fresh QOS query
m_hRequestResultsEvent.Set(); return m_QosDetector.GetResults(); }
//
// Function to retrieve the result of the last QOS query
//
MM_QOS_t MM_GetQos() { return s_QosThread.GetResults(); }
#else
//
// Default implementation of QOS
//
static struct Default_MM_QOS_t : public MM_QOS_t { Default_MM_QOS_t() { nPingMsMin = 50; // 50 ms default ping
nPingMsMed = 50; // 50 ms default ping
flBwUpKbs = 32.0f; // 32 KB/s = 256 kbps
flBwDnKbs = 32.0f; // 32 KB/s = 256 kbps
flLoss = 0.0f; // 0% packet loss
} } s_DefaultQos;
MM_QOS_t MM_GetQos() { return s_DefaultQos; }
#endif
|