mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-08 17:59:37 +00:00
1
This commit is contained in:
@@ -0,0 +1,262 @@
|
||||
//========= 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
|
||||
Reference in New Issue
Block a user