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.
262 lines
5.3 KiB
262 lines
5.3 KiB
//========= Copyright 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 _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 ) |
|
{ |
|
XNetQosRelease( m_pQos ); |
|
m_pQos = NULL; |
|
} |
|
} |
|
|
|
bool CQosDetector::InitiateLookup() |
|
{ |
|
Release(); |
|
|
|
// |
|
// Issue the asynchronous QOS service lookup query |
|
// |
|
XNQOS *pQos = NULL; |
|
INT err = 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
|
|
|