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.

452 lines
11 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #ifdef _WIN32
  7. #if !defined( _X360 )
  8. #include <windows.h>
  9. #endif
  10. #elif defined( _PS3 )
  11. #include <sys/socket.h>
  12. #include <netinet/in.h>
  13. #include "basetypes.h"
  14. #include "ps3/ps3_core.h"
  15. #include "ps3/ps3_win32stubs.h"
  16. #elif defined( POSIX )
  17. #include <sys/socket.h>
  18. #include <netinet/in.h>
  19. #include <pwd.h>
  20. #include <sys/types.h>
  21. #else
  22. #error
  23. #endif
  24. #include "host.h"
  25. #include "quakedef.h"
  26. #include "net.h"
  27. #include "bitbuf.h"
  28. #include "tier0/icommandline.h"
  29. #include "cserserverprotocol_engine.h"
  30. #include "host_phonehome.h"
  31. #include "mathlib/IceKey.H"
  32. #include "blockingudpsocket.h"
  33. #if defined( _X360 )
  34. #include "xbox/xbox_win32stubs.h"
  35. #endif
  36. // memdbgon must be the last include file in a .cpp file!!!
  37. #include "tier0/memdbgon.h"
  38. #define PHONE_HOME_TIMEOUT 1.5f
  39. #define PHONE_HOME_RETRIES 3
  40. //-----------------------------------------------------------------------------
  41. // Purpose: returns a pointer to a function, given a module
  42. // Input : pModuleName - module name
  43. // *pName - proc name
  44. //-----------------------------------------------------------------------------
  45. static char const *g_pszExitMsg = "Renderer: Out of memory, message code %i";
  46. class CPhoneHome : public IPhoneHome
  47. {
  48. public:
  49. CPhoneHome() :
  50. m_bPhoneHome( false ),
  51. m_uSessionID( 0 ),
  52. m_pSocket( 0 )
  53. {
  54. Q_memset( &m_cserIP, 0, sizeof( m_cserIP ) );
  55. Q_memset( m_szBuildIdentifier, 0, sizeof( m_szBuildIdentifier ) );
  56. }
  57. virtual void Shutdown()
  58. {
  59. delete m_pSocket;
  60. m_pSocket = NULL;
  61. }
  62. virtual void Init()
  63. {
  64. char build_identifier[ 32 ];
  65. Q_strncpy( build_identifier, "VLV_INTERNAL ", sizeof( build_identifier ) );
  66. int iBI = CommandLine()->FindParm("-bi");
  67. if ( iBI > 0 )
  68. {
  69. if ( (iBI+1) < CommandLine()->ParmCount() )
  70. {
  71. char const *pBuildParam = CommandLine()->GetParm( iBI + 1 );
  72. Q_memset( build_identifier, 0, sizeof( build_identifier ) );
  73. Q_strncpy( build_identifier, pBuildParam, sizeof( build_identifier ) );
  74. }
  75. else
  76. {
  77. build_identifier[ 0 ] = '!';
  78. }
  79. }
  80. if ( Q_strlen( build_identifier ) >= 1 &&
  81. !StringHasPrefix( build_identifier, "VLV_INTERNAL" ) )
  82. {
  83. // Strip trailing spaces from identifer
  84. char *identifer = &build_identifier[ Q_strlen( build_identifier ) - 1 ];
  85. while ( identifer > build_identifier && *identifer == ' ' )
  86. {
  87. *identifer-- = 0;
  88. }
  89. // FIXME: Don't hardcode CSER ip, get from Steam!!!
  90. if ( NET_StringToAdr( "207.173.177.12:27013", &m_cserIP ) )
  91. {
  92. m_bPhoneHome = true;
  93. Q_strncpy( m_szBuildIdentifier, build_identifier, sizeof( m_szBuildIdentifier ) );
  94. m_pSocket = new CBlockingUDPSocket();
  95. }
  96. }
  97. }
  98. virtual void Message( byte msgtype, char const *mapname )
  99. {
  100. if ( !m_bPhoneHome )
  101. return;
  102. if ( !m_pSocket )
  103. return;
  104. switch ( msgtype )
  105. {
  106. default:
  107. break;
  108. case PHONE_MSG_ENGINESTART:
  109. if ( !RequestSessionId( m_uSessionID ) )
  110. {
  111. ExitApp();
  112. }
  113. // Note we always return here!!!
  114. return;
  115. case PHONE_MSG_ENGINEEND:
  116. break;
  117. case PHONE_MSG_MAPSTART:
  118. {
  119. if ( m_bLevelStarted )
  120. {
  121. return;
  122. }
  123. m_bLevelStarted = true;
  124. // Tracker 22394: Don't send map start/finish when building reslists...
  125. if ( CommandLine()->FindParm( "-makereslists" ) )
  126. {
  127. return;
  128. }
  129. }
  130. break;
  131. case PHONE_MSG_MAPEND:
  132. {
  133. if ( !m_bLevelStarted )
  134. {
  135. return;
  136. }
  137. m_bLevelStarted = false;
  138. // Tracker 22394: Don't send map start/finish when building reslists...
  139. if ( CommandLine()->FindParm( "-makereslists" ) )
  140. {
  141. return;
  142. }
  143. }
  144. break;
  145. }
  146. SendSessionMessage( msgtype, mapname );
  147. }
  148. private:
  149. void ExitApp()
  150. {
  151. byte msgtype = 212;
  152. Error( g_pszExitMsg, msgtype );
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Purpose: encrypts an 8-byte sequence
  156. //-----------------------------------------------------------------------------
  157. inline void Encrypt8ByteSequence( IceKey& cipher, const unsigned char *plainText, unsigned char *cipherText)
  158. {
  159. cipher.encrypt(plainText, cipherText);
  160. }
  161. //-----------------------------------------------------------------------------
  162. // Purpose:
  163. //-----------------------------------------------------------------------------
  164. void EncryptBuffer( IceKey& cipher, unsigned char *bufData, uint bufferSize)
  165. {
  166. unsigned char *cipherText = bufData;
  167. unsigned char *plainText = bufData;
  168. uint bytesEncrypted = 0;
  169. while (bytesEncrypted < bufferSize)
  170. {
  171. // encrypt 8 byte section
  172. Encrypt8ByteSequence( cipher, plainText, cipherText);
  173. bytesEncrypted += 8;
  174. cipherText += 8;
  175. plainText += 8;
  176. }
  177. }
  178. void BuildMessage( bf_write& buf, byte msgtype, char const *mapname, unsigned int uSessionID )
  179. {
  180. bf_write encrypted;
  181. byte encrypted_data[ 2048 ];
  182. buf.WriteByte( C2M_PHONEHOME );
  183. buf.WriteByte( '\n' );
  184. buf.WriteByte( C2M_PHONEHOME_PROTOCOL_VERSION );
  185. buf.WriteLong( uSessionID ); // sessionid (request new id by sending 0)
  186. // encryption object
  187. IceKey cipher(1); /* medium encryption level */
  188. unsigned char ucEncryptionKey[8] = { 191, 1, 0, 222, 85, 39, 154, 1 };
  189. cipher.set( ucEncryptionKey );
  190. encrypted.StartWriting( encrypted_data, sizeof( encrypted_data ) );
  191. byte corruption_identifier = 0x01;
  192. encrypted.WriteByte( corruption_identifier );
  193. // Data version protocol
  194. encrypted.WriteByte( 1 );
  195. // Write the "build identifier" -- unique to each person we give a build to.
  196. encrypted.WriteString( m_szBuildIdentifier );
  197. {
  198. char computername[ 64 ];
  199. Q_memset( computername, 0, sizeof( computername ) );
  200. #if defined ( _WIN32 )
  201. DWORD length = sizeof( computername ) - 1;
  202. if ( !GetComputerName( computername, &length ) )
  203. {
  204. Q_strncpy( computername, "???", sizeof( computername ) );
  205. }
  206. #else
  207. if ( gethostname( computername, sizeof(computername) ) == -1 )
  208. {
  209. Q_strncpy( computername, "Linux????", sizeof( computername ) );
  210. }
  211. computername[sizeof(computername)-1] = '\0';
  212. #endif
  213. encrypted.WriteString( computername );
  214. }
  215. {
  216. char username[ 64 ];
  217. Q_memset( username, 0, sizeof( username ) );
  218. #if defined ( _WIN32 )
  219. DWORD length = sizeof( username ) - 1;
  220. if ( !GetUserName( username, &length ) )
  221. {
  222. Q_strncpy( username, "???", sizeof( username ) );
  223. }
  224. #elif defined( _PS3 )
  225. Q_strncpy( username, "PS3", sizeof( username ) );
  226. #else
  227. struct passwd *pass = getpwuid( getuid() );
  228. if ( pass )
  229. {
  230. Q_strncpy( username, pass->pw_name, sizeof( username ) );
  231. }
  232. else
  233. {
  234. Q_strncpy( username, "LinuxUser??", sizeof( username ) );
  235. }
  236. username[sizeof(username)-1] = '\0';
  237. #endif
  238. encrypted.WriteString( username );
  239. }
  240. char gamedir[ 64 ];
  241. Q_FileBase( com_gamedir, gamedir, sizeof( gamedir ) );
  242. encrypted.WriteString( gamedir );
  243. unsigned int uBuildNumber = build_number();
  244. encrypted.WriteLong( (int)uBuildNumber );
  245. // WRite timestamp of engine
  246. encrypted.WriteFloat( (float)realtime );
  247. encrypted.WriteByte( msgtype );
  248. if ( mapname != NULL )
  249. {
  250. encrypted.WriteString( mapname );
  251. }
  252. int isDebugUser = ( Sys_IsDebuggerPresent() || CommandLine()->FindParm( "-allowdebug" ) ) ? 1 : 0;
  253. encrypted.WriteByte( isDebugUser );
  254. while ( encrypted.GetNumBytesWritten() % 8 )
  255. {
  256. encrypted.WriteByte( 0 );
  257. }
  258. EncryptBuffer( cipher, (unsigned char *)encrypted.GetData(), encrypted.GetNumBytesWritten() );
  259. buf.WriteShort( (int)encrypted.GetNumBytesWritten() );
  260. buf.WriteBytes( (unsigned char *)encrypted.GetData(), encrypted.GetNumBytesWritten() );
  261. }
  262. void SendSessionMessage( byte msgtype, char const *mapname )
  263. {
  264. if ( m_uSessionID == 0 )
  265. return;
  266. bf_write buf;
  267. byte data[ 2048 ];
  268. buf.StartWriting( data, sizeof( data ) );
  269. BuildMessage( buf, msgtype, mapname, m_uSessionID );
  270. struct sockaddr_in sa;
  271. m_cserIP.ToSockadr( (struct sockaddr *)&sa );
  272. m_pSocket->SendSocketMessage( sa, (const byte *)buf.GetData(), buf.GetNumBytesWritten() );
  273. // If we already have a sessionid, don't wait for the server to give us back a new one...
  274. if ( m_uSessionID != 0 )
  275. {
  276. return;
  277. }
  278. if ( m_pSocket->WaitForMessage( PHONE_HOME_TIMEOUT ) )
  279. {
  280. ALIGN4 byte readbuf[ 128 ] ALIGN4_POST;
  281. bf_read replybuf( readbuf, sizeof( readbuf ) );
  282. struct sockaddr_in replyaddress;
  283. uint bytesReceived = m_pSocket->ReceiveSocketMessage( &replyaddress, (byte *)readbuf, sizeof( readbuf ) );
  284. if ( bytesReceived > 0 )
  285. {
  286. // Fixup actual size
  287. replybuf.StartReading( readbuf, bytesReceived );
  288. // Parse out data
  289. byte responseType = (byte)replybuf.ReadByte();
  290. if ( M2C_ACKPHONEHOME == responseType )
  291. {
  292. bool allowPlay = replybuf.ReadByte() == 1 ? true : false;
  293. if ( allowPlay )
  294. {
  295. m_uSessionID = replybuf.ReadLong();
  296. }
  297. }
  298. }
  299. }
  300. }
  301. bool RequestSessionId( unsigned int& id )
  302. {
  303. id = 0u;
  304. bf_write buf;
  305. byte data[ 2048 ];
  306. buf.StartWriting( data, sizeof( data ) );
  307. BuildMessage( buf, PHONE_MSG_ENGINESTART, NULL, id );
  308. struct sockaddr_in sa;
  309. m_cserIP.ToSockadr( (struct sockaddr *)&sa );
  310. for ( int retries = 0; retries < PHONE_HOME_RETRIES; ++retries )
  311. {
  312. m_pSocket->SendSocketMessage( sa, (const byte *)buf.GetData(), buf.GetNumBytesWritten() ); //lint !e534
  313. if ( m_pSocket->WaitForMessage( PHONE_HOME_TIMEOUT ) )
  314. {
  315. ALIGN4 byte readbuf[ 128 ] ALIGN4_POST;
  316. bf_read replybuf( readbuf, sizeof( readbuf ) );
  317. struct sockaddr_in replyaddress;
  318. uint bytesReceived = m_pSocket->ReceiveSocketMessage( &replyaddress, (byte *)readbuf, sizeof( readbuf ) );
  319. if ( bytesReceived > 0 )
  320. {
  321. // Fixup actual size
  322. replybuf.StartReading( readbuf, bytesReceived );
  323. // Parse out data
  324. byte responseType = (byte)replybuf.ReadByte();
  325. if ( M2C_ACKPHONEHOME == responseType )
  326. {
  327. bool allowPlay = replybuf.ReadByte() == 1 ? true : false;
  328. if ( allowPlay )
  329. {
  330. id = replybuf.ReadLong();
  331. return true;
  332. }
  333. }
  334. break;
  335. }
  336. }
  337. }
  338. return false;
  339. }
  340. // FIXME, this is BS
  341. bool IsExternalBuild()
  342. {
  343. if ( CommandLine()->FindParm( "-publicbuild" ) )
  344. {
  345. return true;
  346. }
  347. if ( !CommandLine()->FindParm( "-internalbuild" ) &&
  348. !CommandLine()->CheckParm("-dev") )
  349. {
  350. return true;
  351. }
  352. // It's an external build...
  353. if ( m_bPhoneHome )
  354. {
  355. if ( !Q_stricmp( m_szBuildIdentifier, "beta-playtest" ) )
  356. {
  357. // Still internal
  358. return false;
  359. }
  360. return true;
  361. }
  362. return false;
  363. }
  364. bool m_bPhoneHome;
  365. netadr_t m_cserIP;
  366. char m_szBuildIdentifier[ 32 ];
  367. bool m_bLevelStarted;
  368. unsigned int m_uSessionID;
  369. CBlockingUDPSocket *m_pSocket;
  370. };
  371. CPhoneHome g_PhoneHome;
  372. IPhoneHome *phonehome = &g_PhoneHome;