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.

262 lines
5.4 KiB

  1. //====== Copyright c 1996-2007, Valve Corporation, All rights reserved. =======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "matchmakingqos.h"
  9. #include "threadtools.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. #if defined( _X360 )
  13. //-----------------------------------------------------------------------------
  14. // Quality of Service detection routines
  15. //-----------------------------------------------------------------------------
  16. class CQosDetector
  17. {
  18. public:
  19. CQosDetector();
  20. ~CQosDetector();
  21. public:
  22. bool InitiateLookup();
  23. bool WaitForResults();
  24. public:
  25. MM_QOS_t GetResults() const { return m_Results; }
  26. private:
  27. void Release();
  28. XNQOS *m_pQos;
  29. void ProcessResults();
  30. MM_QOS_t m_Results;
  31. };
  32. CQosDetector::CQosDetector() : m_pQos( NULL )
  33. {
  34. m_Results.nPingMsMin = 50; // 50 ms default ping
  35. m_Results.nPingMsMed = 50; // 50 ms default ping
  36. m_Results.flBwUpKbs = 32.0f; // 32 KB/s = 256 kbps
  37. m_Results.flBwDnKbs = 32.0f; // 32 KB/s = 256 kbps
  38. m_Results.flLoss = 0.0f; // 0% packet loss
  39. }
  40. CQosDetector::~CQosDetector()
  41. {
  42. Release();
  43. }
  44. void CQosDetector::Release()
  45. {
  46. if ( m_pQos )
  47. {
  48. g_pMatchExtensions->GetIXOnline()->XNetQosRelease( m_pQos );
  49. m_pQos = NULL;
  50. }
  51. }
  52. bool CQosDetector::InitiateLookup()
  53. {
  54. Release();
  55. //
  56. // Issue the asynchronous QOS service lookup query
  57. //
  58. XNQOS *pQos = NULL;
  59. INT err = g_pMatchExtensions->GetIXOnline()->XNetQosServiceLookup( NULL, NULL, &pQos );
  60. if ( err )
  61. {
  62. Msg( "CQosDetector::InitiateLookup failed, err = %d\n", err );
  63. return false;
  64. }
  65. if ( !pQos )
  66. {
  67. Msg( "CQosDetector::InitiateLookup failed, qos is null.\n" );
  68. return false;
  69. }
  70. m_pQos = pQos;
  71. return true;
  72. }
  73. bool CQosDetector::WaitForResults()
  74. {
  75. if ( !m_pQos )
  76. return false;
  77. //
  78. // Spin-sleep here while waiting for the probes to come back
  79. //
  80. const int numSecQosTimeout = 30; // Consider QOS query timed out if 30 seconds elapsed
  81. float flTimeStart = Plat_FloatTime(), flTimeEndTimeout = flTimeStart + numSecQosTimeout;
  82. for ( ; ; )
  83. {
  84. if ( Plat_FloatTime() > flTimeEndTimeout )
  85. {
  86. Msg( "CQosDetector::WaitForResults timed out after %d sec.\n", numSecQosTimeout );
  87. Release();
  88. return false; // Timed out
  89. }
  90. if ( m_pQos->axnqosinfo->bFlags & XNET_XNQOSINFO_COMPLETE )
  91. break; // QOS query has completed
  92. ThreadSleep( 10 );
  93. }
  94. if ( ! ( m_pQos->axnqosinfo->bFlags & XNET_XNQOSINFO_TARGET_CONTACTED ) ||
  95. ( m_pQos->axnqosinfo->bFlags & XNET_XNQOSINFO_TARGET_DISABLED ) )
  96. {
  97. // Failed to contact host or target disabled
  98. Msg( "CQosDetector::WaitForResults host unavailable.\n" );
  99. Release();
  100. return false;
  101. }
  102. ProcessResults();
  103. Release();
  104. return true;
  105. }
  106. void CQosDetector::ProcessResults()
  107. {
  108. MM_QOS_t Results;
  109. Results.nPingMsMin = m_pQos->axnqosinfo->wRttMinInMsecs;
  110. Results.nPingMsMed = m_pQos->axnqosinfo->wRttMedInMsecs;
  111. Results.flBwUpKbs = m_pQos->axnqosinfo->dwUpBitsPerSec / 8192.0f;
  112. if ( Results.flBwUpKbs < 1.f )
  113. {
  114. Results.flBwUpKbs = 1.f;
  115. }
  116. Results.flBwDnKbs = m_pQos->axnqosinfo->dwDnBitsPerSec / 8192.0f;
  117. if ( Results.flBwDnKbs < 1.f )
  118. {
  119. Results.flBwDnKbs = 1.f;
  120. }
  121. Results.flLoss = m_pQos->axnqosinfo->cProbesXmit ? ( float( m_pQos->axnqosinfo->cProbesXmit - m_pQos->axnqosinfo->cProbesRecv ) * 100.f / m_pQos->axnqosinfo->cProbesXmit ) : 0.f;
  122. m_Results = Results;
  123. // Dump the results
  124. Msg(
  125. "[QOS] Fresh QOS results available:\n"
  126. "[QOS] ping %d min, %d med\n"
  127. "[QOS] bandwidth %.1f kB/s upstream, %.1f kB/s downstream\n"
  128. "[QOS] avg packet loss %.0f percents\n",
  129. Results.nPingMsMin, Results.nPingMsMed,
  130. Results.flBwUpKbs, Results.flBwDnKbs,
  131. Results.flLoss
  132. );
  133. }
  134. //
  135. // Global QOS detector thread
  136. //
  137. static class CQosThread
  138. {
  139. public:
  140. CQosThread();
  141. MM_QOS_t GetResults();
  142. static unsigned ThreadProc( void *pThis ) { return ( (CQosThread *) pThis )->Run(), 0; }
  143. void Run();
  144. private:
  145. ThreadHandle_t m_hHandle;
  146. CThreadEvent m_hRequestResultsEvent; // Auto reset event to trigger next query
  147. CQosDetector m_QosDetector;
  148. }
  149. s_QosThread;
  150. CQosThread::CQosThread() : m_hHandle( NULL )
  151. {
  152. }
  153. void CQosThread::Run()
  154. {
  155. //
  156. // Sit here and fetch fresh QOS results whenever somebody needs them.
  157. // Every request of QOS data is instantaneous and returns the last successful QOS query result.
  158. //
  159. for ( unsigned int numQosRequestsMade = 0; ; ++ numQosRequestsMade )
  160. {
  161. m_QosDetector.InitiateLookup();
  162. m_QosDetector.WaitForResults();
  163. if ( numQosRequestsMade )
  164. {
  165. m_hRequestResultsEvent.Wait();
  166. }
  167. }
  168. ReleaseThreadHandle( m_hHandle );
  169. m_hHandle = NULL;
  170. }
  171. MM_QOS_t CQosThread::GetResults()
  172. {
  173. // Launch the thread if this is the first time QOS is needed
  174. if ( !m_hHandle )
  175. {
  176. m_hHandle = CreateSimpleThread( ThreadProc, this );
  177. if( m_hHandle )
  178. {
  179. ThreadSetAffinity( m_hHandle, XBOX_PROCESSOR_3 );
  180. }
  181. }
  182. // Signal the event that we can make a fresh QOS query
  183. m_hRequestResultsEvent.Set();
  184. return m_QosDetector.GetResults();
  185. }
  186. //
  187. // Function to retrieve the result of the last QOS query
  188. //
  189. MM_QOS_t MM_GetQos()
  190. {
  191. return s_QosThread.GetResults();
  192. }
  193. #else
  194. //
  195. // Default implementation of QOS
  196. //
  197. static struct Default_MM_QOS_t : public MM_QOS_t
  198. {
  199. Default_MM_QOS_t()
  200. {
  201. nPingMsMin = 50; // 50 ms default ping
  202. nPingMsMed = 50; // 50 ms default ping
  203. flBwUpKbs = 32.0f; // 32 KB/s = 256 kbps
  204. flBwDnKbs = 32.0f; // 32 KB/s = 256 kbps
  205. flLoss = 0.0f; // 0% packet loss
  206. }
  207. }
  208. s_DefaultQos;
  209. MM_QOS_t MM_GetQos()
  210. {
  211. return s_DefaultQos;
  212. }
  213. #endif