Team Fortress 2 Source Code as on 22/4/2020
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.

337 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: steam state machine that handles authenticating steam users
  4. //
  5. //=============================================================================//
  6. #ifdef _WIN32
  7. #if !defined( _X360 )
  8. #include "winlite.h"
  9. #include <winsock2.h> // INADDR_ANY defn
  10. #endif
  11. #elif POSIX
  12. #include <netinet/in.h>
  13. #endif
  14. #include <utlbuffer.h>
  15. #include "cl_steamauth.h"
  16. #include "interface.h"
  17. #include "filesystem_engine.h"
  18. #include "tier0/icommandline.h"
  19. #include "tier0/vprof.h"
  20. #include "host.h"
  21. #include "cmd.h"
  22. #include "common.h"
  23. #ifndef SWDS
  24. #include "vgui_baseui_interface.h"
  25. #endif
  26. #pragma warning( disable: 4355 ) // disables ' 'this' : used in base member initializer list'
  27. //-----------------------------------------------------------------------------
  28. // Purpose: singleton accessor
  29. //-----------------------------------------------------------------------------
  30. static CSteam3Client s_Steam3Client;
  31. CSteam3Client &Steam3Client()
  32. {
  33. return s_Steam3Client;
  34. }
  35. //-----------------------------------------------------------------------------
  36. // Purpose: Constructor
  37. //-----------------------------------------------------------------------------
  38. CSteam3Client::CSteam3Client()
  39. #if !defined(NO_STEAM)
  40. :
  41. m_CallbackClientGameServerDeny( this, &CSteam3Client::OnClientGameServerDeny ),
  42. m_CallbackGameServerChangeRequested( this, &CSteam3Client::OnGameServerChangeRequested ),
  43. m_CallbackGameOverlayActivated( this, &CSteam3Client::OnGameOverlayActivated ),
  44. m_CallbackPersonaStateChanged( this, &CSteam3Client::OnPersonaUpdated ),
  45. m_CallbackLowBattery( this, &CSteam3Client::OnLowBattery )
  46. #endif
  47. {
  48. m_bActive = false;
  49. m_bGSSecure = false;
  50. m_hAuthTicket = k_HAuthTicketInvalid;
  51. m_unIP = 0;
  52. m_usPort = 0;
  53. m_nTicketSize = 0;
  54. }
  55. //-----------------------------------------------------------------------------
  56. // Purpose: Destructor
  57. //-----------------------------------------------------------------------------
  58. CSteam3Client::~CSteam3Client()
  59. {
  60. Shutdown();
  61. }
  62. //-----------------------------------------------------------------------------
  63. // Purpose: Unload the steam3 engine
  64. //-----------------------------------------------------------------------------
  65. void CSteam3Client::Shutdown()
  66. {
  67. if ( !m_bActive )
  68. return;
  69. m_bActive = false;
  70. #if !defined( NO_STEAM )
  71. SteamAPI_Shutdown();
  72. Clear(); // clear our interface pointers now they are invalid
  73. #endif
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Purpose: Initialize the steam3 connection
  77. //-----------------------------------------------------------------------------
  78. void CSteam3Client::Activate()
  79. {
  80. if ( m_bActive )
  81. return;
  82. m_bActive = true;
  83. m_bGSSecure = false;
  84. #if !defined( NO_STEAM )
  85. SteamAPI_InitSafe(); // ignore failure, that will fall out later when they don't get a valid logon cookie
  86. SteamAPI_SetTryCatchCallbacks( false ); // We don't use exceptions, so tell steam not to use try/catch in callback handlers
  87. Init(); // Steam API context init
  88. #endif
  89. }
  90. //-----------------------------------------------------------------------------
  91. // Purpose: Get the steam3 logon cookie to use
  92. //-----------------------------------------------------------------------------
  93. void CSteam3Client::GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket, uint32 unIP, uint16 usPort, uint64 unGSSteamID, bool bSecure )
  94. {
  95. #ifdef NO_STEAM
  96. m_bGSSecure = bSecure;
  97. #else
  98. CSteamID steamIDGS( unGSSteamID );
  99. // Assume failure
  100. *pcbTicket = 0;
  101. // We must have interface pointers
  102. if ( !SteamUser() )
  103. {
  104. Warning( "No SteamUser interface. Cannot perform steam authentication\n" );
  105. return;
  106. }
  107. // Make sure we have a valid Steam ID
  108. CSteamID steamID = SteamUser()->GetSteamID();
  109. if ( !steamID.IsValid() )
  110. {
  111. Warning( "Our steam ID %s is not valid. Steam must be running and you must be logged in\n", steamID.Render() );
  112. return;
  113. }
  114. // Get a new ticket, if we don't already have one for this server
  115. if ( m_hAuthTicket == k_HAuthTicketInvalid
  116. || m_unIP != unIP
  117. || m_usPort != usPort
  118. || m_bGSSecure != bSecure
  119. || m_steamIDGS != steamIDGS
  120. || m_nTicketSize <= 0 )
  121. {
  122. // Cancel any previously issues ticket
  123. if ( m_hAuthTicket != k_HAuthTicketInvalid )
  124. SteamUser()->CancelAuthTicket( m_hAuthTicket );
  125. // Shove the GS ID in the first bits
  126. *(uint64*)m_arbTicketData = SteamUser()->GetSteamID().ConvertToUint64();
  127. // Ask Steam for a ticket
  128. m_nTicketSize = 0;
  129. m_hAuthTicket = SteamUser()->GetAuthSessionTicket( m_arbTicketData+sizeof(uint64), sizeof(m_arbTicketData)-sizeof(uint64), &m_nTicketSize );
  130. if ( m_hAuthTicket == k_HAuthTicketInvalid || m_nTicketSize <= 0 )
  131. {
  132. // Failed!
  133. Assert( m_hAuthTicket != k_HAuthTicketInvalid );
  134. Assert( m_nTicketSize > 0 );
  135. m_hAuthTicket = k_HAuthTicketInvalid;
  136. m_nTicketSize = 0;
  137. Warning( "ISteamUser::GetAuthSessionTicket failed to return a valid ticket\n" );
  138. }
  139. else
  140. {
  141. // Got valid ticket. Remember its properties
  142. m_nTicketSize += sizeof(uint64);
  143. m_unIP = unIP;
  144. m_usPort = usPort;
  145. m_bGSSecure = bSecure;
  146. m_steamIDGS = steamIDGS;
  147. }
  148. }
  149. // Give them back the ticket data, if we were able to get one, and it will fit
  150. *pcbTicket = 0;
  151. if ( m_nTicketSize > 0 )
  152. {
  153. if ( cbMaxTicket >= (int)m_nTicketSize )
  154. {
  155. memcpy( pTicket, m_arbTicketData, m_nTicketSize );
  156. *pcbTicket = m_nTicketSize;
  157. }
  158. else
  159. {
  160. Assert( cbMaxTicket >= (int)m_nTicketSize );
  161. }
  162. }
  163. // Tell the steam backend about the server we are playing on - so that it can broadcast this to our friends and they can join.
  164. // This may be something that you should NOT do if you are on a listen server - or you know that the game is not joinable
  165. // for some reason.
  166. #ifdef _DEBUG
  167. Msg( "Sending AdvertiseGame %s %s (%s)\n", steamIDGS.Render(), netadr_t(unIP, usPort).ToString(), m_bGSSecure ? "secure" : "insecure" );
  168. #endif
  169. SteamUser()->AdvertiseGame( steamIDGS, unIP, usPort );
  170. #endif
  171. }
  172. //-----------------------------------------------------------------------------
  173. // Purpose: Tell steam that we are leaving a server
  174. //-----------------------------------------------------------------------------
  175. void CSteam3Client::CancelAuthTicket()
  176. {
  177. m_bGSSecure = false;
  178. if ( !SteamUser() )
  179. return;
  180. #if !defined( NO_STEAM )
  181. if ( m_hAuthTicket != k_HAuthTicketInvalid )
  182. SteamUser()->CancelAuthTicket( m_hAuthTicket );
  183. #ifdef _DEBUG
  184. Msg( "Clearing auth ticket, sending void AdvertiseGame\n" );
  185. #endif
  186. CSteamID steamIDGS; // invalid steamID means not playing anywhere
  187. SteamUser()->AdvertiseGame( steamIDGS, 0, 0 );
  188. m_hAuthTicket = k_HAuthTicketInvalid;
  189. #endif
  190. }
  191. //-----------------------------------------------------------------------------
  192. // Purpose: Process any callbacks we may have
  193. //-----------------------------------------------------------------------------
  194. void CSteam3Client::RunFrame()
  195. {
  196. #if !defined( NO_STEAM )
  197. VPROF_BUDGET( "CSteam3Client::RunFrame", VPROF_BUDGETGROUP_STEAM );
  198. SteamAPI_RunCallbacks();
  199. #endif
  200. }
  201. #if !defined(NO_STEAM)
  202. //-----------------------------------------------------------------------------
  203. // Purpose: Disconnect the user from their current server
  204. //-----------------------------------------------------------------------------
  205. void CSteam3Client::OnClientGameServerDeny( ClientGameServerDeny_t *pClientGameServerDeny )
  206. {
  207. if ( pClientGameServerDeny->m_uAppID == GetSteamAppID() )
  208. {
  209. const char *pszReason = "Unknown";
  210. switch ( pClientGameServerDeny->m_uReason )
  211. {
  212. case ( k_EDenyInvalidVersion ) : pszReason = "Invalid version"; break;
  213. case ( k_EDenyGeneric ) : pszReason = "Kicked"; break;
  214. case ( k_EDenyNotLoggedOn ) : pszReason = "Not logged on"; break;
  215. case ( k_EDenyNoLicense ) : pszReason = "No license"; break;
  216. case ( k_EDenyCheater ) : pszReason = "VAC banned "; break;
  217. case ( k_EDenyLoggedInElseWhere ) : pszReason = "Dropped from server"; break;
  218. case ( k_EDenyUnknownText ) : pszReason = "Unknown"; break;
  219. case ( k_EDenyIncompatibleAnticheat ) : pszReason = "Incompatible Anti Cheat"; break;
  220. case ( k_EDenyMemoryCorruption ) : pszReason = "Memory corruption"; break;
  221. case ( k_EDenyIncompatibleSoftware ) : pszReason = "Incompatible software"; break;
  222. case ( k_EDenySteamConnectionLost ) : pszReason = "Steam connection lost"; break;
  223. case ( k_EDenySteamConnectionError ) : pszReason = "Steam connection error"; break;
  224. case ( k_EDenySteamResponseTimedOut ) : pszReason = "Response timed out"; break;
  225. case ( k_EDenySteamValidationStalled ) : pszReason = "Verification failed"; break;
  226. }
  227. Warning( "Disconnect: %s\n", pszReason );
  228. Host_Disconnect( true );
  229. }
  230. }
  231. extern ConVar password;
  232. //-----------------------------------------------------------------------------
  233. // Purpose: Disconnect the user from their current server
  234. //-----------------------------------------------------------------------------
  235. void CSteam3Client::OnGameServerChangeRequested( GameServerChangeRequested_t *pGameServerChangeRequested )
  236. {
  237. password.SetValue( pGameServerChangeRequested->m_rgchPassword );
  238. Msg( "Connecting to %s\n", pGameServerChangeRequested->m_rgchServer );
  239. Cbuf_AddText( va( "connect %s steam\n", pGameServerChangeRequested->m_rgchServer ) );
  240. }
  241. //-----------------------------------------------------------------------------
  242. // Purpose:
  243. //-----------------------------------------------------------------------------
  244. void CSteam3Client::OnGameOverlayActivated( GameOverlayActivated_t *pGameOverlayActivated )
  245. {
  246. #ifndef SWDS
  247. if ( Host_IsSinglePlayerGame() )
  248. {
  249. if ( !EngineVGui()->IsGameUIVisible() &&
  250. !EngineVGui()->IsConsoleVisible() )
  251. {
  252. if ( pGameOverlayActivated->m_bActive )
  253. Cbuf_AddText( "setpause" );
  254. else
  255. Cbuf_AddText( "unpause" );
  256. }
  257. }
  258. #endif
  259. }
  260. extern void UpdateNameFromSteamID( IConVar *pConVar, CSteamID *pSteamID );
  261. //-----------------------------------------------------------------------------
  262. // Purpose:
  263. //-----------------------------------------------------------------------------
  264. void CSteam3Client::OnPersonaUpdated( PersonaStateChange_t *pPersonaStateChanged )
  265. {
  266. if ( pPersonaStateChanged->m_nChangeFlags & k_EPersonaChangeName )
  267. {
  268. if ( SteamUtils() && SteamFriends() && SteamUser() )
  269. {
  270. CSteamID steamID = SteamUser()->GetSteamID();
  271. IConVar *pConVar = g_pCVar->FindVar( "name" );
  272. UpdateNameFromSteamID( pConVar, &steamID );
  273. }
  274. }
  275. }
  276. //-----------------------------------------------------------------------------
  277. // Purpose:
  278. //-----------------------------------------------------------------------------
  279. void CSteam3Client::OnLowBattery( LowBatteryPower_t *pLowBat )
  280. {
  281. // on the 9min, 5 min and 1 min warnings tell the engine to fire off a save
  282. switch( pLowBat->m_nMinutesBatteryLeft )
  283. {
  284. case 9:
  285. case 5:
  286. case 1:
  287. Cbuf_AddText( "save LowBattery_AutoSave" );
  288. break;
  289. default:
  290. break;
  291. }
  292. }
  293. #endif