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.

969 lines
27 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "basetypes.h"
  9. #ifdef WIN32
  10. #include <winsock.h>
  11. #elif defined(POSIX)
  12. #define INVALID_SOCKET -1
  13. #define SOCKET_ERROR -1
  14. #include <sys/types.h>
  15. #include <sys/socket.h>
  16. #include <netinet/in.h>
  17. #define closesocket close
  18. #else
  19. #error
  20. #endif
  21. #include "netadr.h"
  22. #include "tier1/strtools.h"
  23. #include <stdio.h>
  24. #include <stdarg.h>
  25. #include "utlbuffer.h"
  26. #include "utlvector.h"
  27. #include "filesystem_tools.h"
  28. #include "cserserverprotocol_engine.h"
  29. #include "mathlib/IceKey.H"
  30. #include "bitbuf.h"
  31. #include "blockingudpsocket.h"
  32. #include "steamcommon.h"
  33. #include "steam/steamclientpublic.h"
  34. typedef unsigned int u32;
  35. typedef unsigned char u8;
  36. typedef unsigned short u16;
  37. namespace BugReportHarvester
  38. {
  39. enum EFileType
  40. {
  41. eFileTypeBugReport,
  42. eFILETYPECOUNT // Count number of legal values
  43. };
  44. enum ESendMethod
  45. {
  46. eSendMethodWholeRawFileNoBlocks,
  47. eSendMethodCompressedBlocks, // TODO: Reenable compressed sending of minidumps
  48. eSENDMETHODCOUNT // Count number of legal values
  49. };
  50. }
  51. using namespace BugReportHarvester;
  52. // TODO: cut protocol version down to u8 if possible, to reduce bandwidth usage
  53. // for very frequent but tiny commands.
  54. typedef u32 ProtocolVersion_t;
  55. typedef u8 ProtocolAcceptanceFlag_t;
  56. typedef u8 ProtocolUnacceptableAck_t;
  57. typedef u32 MessageSequenceId_t;
  58. typedef u32 ServerSessionHandle_t;
  59. typedef u32 ClientSessionHandle_t;
  60. typedef u32 NetworkTransactionId_t;
  61. // Command codes are intentionally as small as possible to minimize bandwidth usage
  62. // for very frequent but tiny commands (e.g. GDS 'FindServer' commands).
  63. typedef u8 Command_t;
  64. // ... likewise response codes are as small as possible - we use this when we
  65. // ... can and revert to large types on a case by case basis.
  66. typedef u8 CommandResponse_t;
  67. // This define our standard type for length prefix for variable length messages
  68. // in wire protocols.
  69. // This is specifically used by CWSABUFWrapper::PrepareToReceiveLengthPrefixedMessage()
  70. // and its supporting functions.
  71. // It is defined here for generic (portable) network code to use when constructing
  72. // messages to be sent to peers that use the above function.
  73. // e.g. SteamValidateUserIDTickets.dll uses this for that purpose.
  74. // We support u16 or u32 (obviously switching between them breaks existing protocols
  75. // unless all components are switched simultaneously).
  76. typedef u32 NetworkMessageLengthPrefix_t;
  77. // Similarly, strings should be preceeded by their length.
  78. typedef u16 StringLengthPrefix_t;
  79. const ProtocolAcceptanceFlag_t cuProtocolIsNotAcceptable
  80. = static_cast<ProtocolAcceptanceFlag_t>( 0 );
  81. const ProtocolAcceptanceFlag_t cuProtocolIsAcceptable
  82. = static_cast<ProtocolAcceptanceFlag_t>( 1 );
  83. const Command_t cuMaxCommand
  84. = static_cast<Command_t>(255);
  85. const CommandResponse_t cuMaxCommandResponse
  86. = static_cast<CommandResponse_t>(255);
  87. // This is for mapping requests back to error ids for placing into the database appropriately.
  88. typedef u32 ContextID_t;
  89. // This is the version of the protocol used by latest-build clients.
  90. const ProtocolVersion_t cuCurrentProtocolVersion = 1;
  91. // This is the minimum protocol version number that the client must
  92. // be able to speak in order to communicate with the server.
  93. // The client sends its protocol version this before every command, and if we
  94. // don't support that version anymore then we tell it nicely. The client
  95. // should respond by doing an auto-update.
  96. const ProtocolVersion_t cuRequiredProtocolVersion = 1;
  97. namespace Commands
  98. {
  99. const Command_t cuGracefulClose = 0;
  100. const Command_t cuSendBugReport = 1;
  101. const Command_t cuNumCommands = 2;
  102. const Command_t cuNoCommandReceivedYet = cuMaxCommand;
  103. }
  104. namespace HarvestFileCommand
  105. {
  106. typedef u32 SenderTypeId_t;
  107. typedef u32 SenderTypeUniqueId_t;
  108. typedef u32 SenderSourceCodeControlId_t;
  109. typedef u32 FileSize_t;
  110. // Legal values defined by EFileType
  111. typedef u32 FileType_t;
  112. // Legal values defined by ESendMethod
  113. typedef u32 SendMethod_t;
  114. const CommandResponse_t cuOkToSendFile = 0;
  115. const CommandResponse_t cuFileTooBig = 1;
  116. const CommandResponse_t cuInvalidSendMethod = 2;
  117. const CommandResponse_t cuInvalidMaxCompressedChunkSize = 3;
  118. const CommandResponse_t cuInvalidBugReportContext = 4;
  119. const uint cuNumCommandResponses = 5;
  120. }
  121. //#############################################################################
  122. //
  123. // Class declaration: CWin32UploadBugReport
  124. //
  125. //#############################################################################
  126. //
  127. // Authors:
  128. //
  129. // Yahn Bernier
  130. //
  131. // Description and general notes:
  132. //
  133. // Handles uploading bug report data blobs to the CSERServer
  134. // (Client Stats & Error Reporting Server)
  135. typedef enum
  136. {
  137. // General status
  138. eBugReportUploadSucceeded = 0,
  139. eBugReportUploadFailed,
  140. // Specific status
  141. eBugReportBadParameter,
  142. eBugReportUnknownStatus,
  143. eBugReportSendingBugReportHeaderSucceeded,
  144. eBugReportSendingBugReportHeaderFailed,
  145. eBugReportReceivingResponseSucceeded,
  146. eBugReportReceivingResponseFailed,
  147. eBugReportConnectToCSERServerSucceeded,
  148. eBugReportConnectToCSERServerFailed,
  149. eBugReportUploadingBugReportSucceeded,
  150. eBugReportUploadingBugReportFailed
  151. } EBugReportUploadStatus;
  152. struct TBugReportProgress
  153. {
  154. // A text string describing the current progress
  155. char m_sStatus[ 512 ];
  156. };
  157. typedef void ( *BUGREPORTREPORTPROGRESSFUNC )( u32 uContext, const TBugReportProgress & rBugReportProgress );
  158. static void BugUploadProgress( u32 uContext, const TBugReportProgress & rBugReportProgress )
  159. {
  160. // DevMsg( "%s\n", rBugReportProgress.m_sStatus );
  161. }
  162. struct TBugReportParameters
  163. {
  164. // IP Address of the CSERServer to send the report to
  165. netadr_t m_ipCSERServer;
  166. TSteamGlobalUserID m_userid;
  167. // Source Control Id (or build_number) of the product
  168. u32 m_uEngineBuildNumber;
  169. // Name of the .exe
  170. char m_sExecutableName[ 64 ];
  171. // Game directory
  172. char m_sGameDirectory[ 64 ];
  173. // Map name the server wants to upload statistics about
  174. char m_sMapName[ 64 ];
  175. u32 m_uRAM;
  176. u32 m_uCPU;
  177. char m_sProcessor[ 128 ];
  178. u32 m_uDXVersionHigh;
  179. u32 m_uDXVersionLow;
  180. u32 m_uDXVendorId;
  181. u32 m_uDXDeviceId;
  182. char m_sOSVersion[ 64 ];
  183. char m_sReportType[ 40 ];
  184. char m_sEmail[ 80 ];
  185. char m_sAccountName[ 64 ];
  186. char m_sTitle[ 128 ];
  187. char m_sBody[ 1024 ];
  188. u32 m_uAttachmentFileSize;
  189. char m_sAttachmentFile[ 128 ];
  190. u32 m_uProgressContext;
  191. BUGREPORTREPORTPROGRESSFUNC m_pOptionalProgressFunc;
  192. };
  193. // Note that this API is blocking, though the callback, if passed, can occur during execution.
  194. EBugReportUploadStatus Win32UploadBugReportBlocking
  195. (
  196. const TBugReportParameters & rBugReportParameters // Input
  197. );
  198. //-----------------------------------------------------------------------------
  199. // Purpose: encrypts an 8-byte sequence
  200. //-----------------------------------------------------------------------------
  201. inline void Encrypt8ByteSequence( IceKey& cipher, const unsigned char *plainText, unsigned char *cipherText)
  202. {
  203. cipher.encrypt(plainText, cipherText);
  204. }
  205. //-----------------------------------------------------------------------------
  206. // Purpose:
  207. //-----------------------------------------------------------------------------
  208. void EncryptBuffer( IceKey& cipher, unsigned char *bufData, uint bufferSize)
  209. {
  210. unsigned char *cipherText = bufData;
  211. unsigned char *plainText = bufData;
  212. uint bytesEncrypted = 0;
  213. while (bytesEncrypted < bufferSize)
  214. {
  215. // encrypt 8 byte section
  216. Encrypt8ByteSequence( cipher, plainText, cipherText);
  217. bytesEncrypted += 8;
  218. cipherText += 8;
  219. plainText += 8;
  220. }
  221. }
  222. bool UploadBugReport(
  223. const netadr_t& cserIP,
  224. const CSteamID &userid,
  225. int build,
  226. char const *title,
  227. char const *body,
  228. char const *exename,
  229. char const *pchGamedir,
  230. char const *mapname,
  231. char const *reporttype,
  232. char const *email,
  233. char const *accountname,
  234. int ram,
  235. int cpu,
  236. char const *processor,
  237. unsigned int high,
  238. unsigned int low,
  239. unsigned int vendor,
  240. unsigned int device,
  241. char const *osversion,
  242. char const *attachedfile,
  243. unsigned int attachedfilesize
  244. )
  245. {
  246. TBugReportParameters params;
  247. Q_memset( &params, 0, sizeof( params ) );
  248. params.m_ipCSERServer = cserIP;
  249. params.m_userid.m_SteamLocalUserID.As64bits = userid.ConvertToUint64();
  250. params.m_uEngineBuildNumber = build;
  251. Q_strncpy( params.m_sExecutableName, exename, sizeof( params.m_sExecutableName ) );
  252. Q_strncpy( params.m_sGameDirectory, pchGamedir, sizeof( params.m_sGameDirectory ) );
  253. Q_strncpy( params.m_sMapName, mapname, sizeof( params.m_sMapName ) );
  254. params.m_uRAM = ram;
  255. params.m_uCPU = cpu;
  256. Q_strncpy( params.m_sProcessor, processor, sizeof( params.m_sProcessor) );
  257. params.m_uDXVersionHigh = high;
  258. params.m_uDXVersionLow = low;
  259. params.m_uDXVendorId = vendor;
  260. params.m_uDXDeviceId = device;
  261. Q_strncpy( params.m_sOSVersion, osversion, sizeof( params.m_sOSVersion ) );
  262. Q_strncpy( params.m_sReportType, reporttype, sizeof( params.m_sReportType ) );
  263. Q_strncpy( params.m_sEmail, email, sizeof( params.m_sEmail ) );
  264. Q_strncpy( params.m_sAccountName, accountname, sizeof( params.m_sAccountName ) );
  265. Q_strncpy( params.m_sTitle, title, sizeof( params.m_sTitle ) );
  266. Q_strncpy( params.m_sBody, body, sizeof( params.m_sBody ) );
  267. Q_strncpy( params.m_sAttachmentFile, attachedfile, sizeof( params.m_sAttachmentFile ) );
  268. params.m_uAttachmentFileSize = attachedfilesize;
  269. params.m_uProgressContext = 1u;
  270. params.m_pOptionalProgressFunc = BugUploadProgress;
  271. EBugReportUploadStatus result = Win32UploadBugReportBlocking( params );
  272. return ( result == eBugReportUploadSucceeded ) ? true : false;
  273. }
  274. void UpdateProgress( const TBugReportParameters & params, char const *fmt, ... )
  275. {
  276. if ( !params.m_pOptionalProgressFunc )
  277. {
  278. return;
  279. }
  280. char str[ 2048 ];
  281. va_list argptr;
  282. va_start( argptr, fmt );
  283. _vsnprintf( str, sizeof( str ) - 1, fmt, argptr );
  284. va_end( argptr );
  285. char outstr[ 2060 ];
  286. Q_snprintf( outstr, sizeof( outstr ), "(%u): %s", params.m_uProgressContext, str );
  287. TBugReportProgress progress;
  288. Q_strncpy( progress.m_sStatus, outstr, sizeof( progress.m_sStatus ) );
  289. // Invoke the callback
  290. ( *params.m_pOptionalProgressFunc )( params.m_uProgressContext, progress );
  291. }
  292. class CWin32UploadBugReport
  293. {
  294. public:
  295. explicit CWin32UploadBugReport(
  296. const netadr_t & harvester,
  297. const TBugReportParameters & rBugReportParameters,
  298. u32 contextid );
  299. ~CWin32UploadBugReport();
  300. EBugReportUploadStatus Upload( CUtlBuffer& buf );
  301. private:
  302. enum States
  303. {
  304. eCreateTCPSocket = 0,
  305. eConnectToHarvesterServer,
  306. eSendProtocolVersion,
  307. eReceiveProtocolOkay,
  308. eSendUploadCommand,
  309. eReceiveOKToSendFile,
  310. eSendWholeFile, // This could push chunks onto the wire, but we'll just use a whole buffer for now.
  311. eReceiveFileUploadSuccess,
  312. eSendGracefulClose,
  313. eCloseTCPSocket
  314. };
  315. bool CreateTCPSocket( EBugReportUploadStatus& status, CUtlBuffer& buf );
  316. bool ConnectToHarvesterServer( EBugReportUploadStatus& status, CUtlBuffer& buf );
  317. bool SendProtocolVersion( EBugReportUploadStatus& status, CUtlBuffer& buf );
  318. bool ReceiveProtocolOkay( EBugReportUploadStatus& status, CUtlBuffer& buf );
  319. bool SendUploadCommand( EBugReportUploadStatus& status, CUtlBuffer& buf );
  320. bool ReceiveOKToSendFile( EBugReportUploadStatus& status, CUtlBuffer& buf );
  321. bool SendWholeFile( EBugReportUploadStatus& status, CUtlBuffer& buf );
  322. bool ReceiveFileUploadSuccess( EBugReportUploadStatus& status, CUtlBuffer& buf );
  323. bool SendGracefulClose( EBugReportUploadStatus& status, CUtlBuffer& buf );
  324. bool CloseTCPSocket( EBugReportUploadStatus& status, CUtlBuffer& buf );
  325. typedef bool ( CWin32UploadBugReport::*pfnProtocolStateHandler )( EBugReportUploadStatus& status, CUtlBuffer& buf );
  326. struct FSMState_t
  327. {
  328. FSMState_t( uint f, pfnProtocolStateHandler s ) :
  329. first( f ),
  330. second( s )
  331. {
  332. }
  333. uint first;
  334. pfnProtocolStateHandler second;
  335. };
  336. void AddState( uint StateIndex, pfnProtocolStateHandler handler );
  337. void SetNextState( uint StateIndex );
  338. bool DoBlockingReceive( uint bytesExpected, CUtlBuffer& buf );
  339. CUtlVector< FSMState_t > m_States;
  340. uint m_uCurrentState;
  341. struct sockaddr_in m_HarvesterSockAddr;
  342. uint m_SocketTCP;
  343. const TBugReportParameters &m_rBugReportParameters; //lint !e1725
  344. u32 m_ContextID;
  345. };
  346. CWin32UploadBugReport::CWin32UploadBugReport(
  347. const netadr_t & harvester,
  348. const TBugReportParameters & rBugReportParameters,
  349. u32 contextid ) :
  350. m_States(),
  351. m_uCurrentState( eCreateTCPSocket ),
  352. m_HarvesterSockAddr(),
  353. m_SocketTCP( 0 ),
  354. m_rBugReportParameters( rBugReportParameters ),
  355. m_ContextID( contextid )
  356. {
  357. harvester.ToSockadr( (struct sockaddr *)&m_HarvesterSockAddr );
  358. AddState( eCreateTCPSocket, &CWin32UploadBugReport::CreateTCPSocket );
  359. AddState( eConnectToHarvesterServer, &CWin32UploadBugReport::ConnectToHarvesterServer );
  360. AddState( eSendProtocolVersion, &CWin32UploadBugReport::SendProtocolVersion );
  361. AddState( eReceiveProtocolOkay, &CWin32UploadBugReport::ReceiveProtocolOkay );
  362. AddState( eSendUploadCommand, &CWin32UploadBugReport::SendUploadCommand );
  363. AddState( eReceiveOKToSendFile, &CWin32UploadBugReport::ReceiveOKToSendFile );
  364. AddState( eSendWholeFile, &CWin32UploadBugReport::SendWholeFile );
  365. AddState( eReceiveFileUploadSuccess, &CWin32UploadBugReport::ReceiveFileUploadSuccess );
  366. AddState( eSendGracefulClose, &CWin32UploadBugReport::SendGracefulClose );
  367. AddState( eCloseTCPSocket, &CWin32UploadBugReport::CloseTCPSocket );
  368. }
  369. CWin32UploadBugReport::~CWin32UploadBugReport()
  370. {
  371. if ( m_SocketTCP != 0 )
  372. {
  373. closesocket( m_SocketTCP ); //lint !e534
  374. m_SocketTCP = 0;
  375. }
  376. }
  377. //-----------------------------------------------------------------------------
  378. //
  379. // Function: DoBlockingReceive()
  380. //
  381. //-----------------------------------------------------------------------------
  382. bool CWin32UploadBugReport::DoBlockingReceive( uint bytesExpected, CUtlBuffer& buf )
  383. {
  384. uint totalReceived = 0;
  385. buf.Purge();
  386. for ( ;; )
  387. {
  388. char temp[ 8192 ];
  389. int bytesReceived = recv( m_SocketTCP, temp, sizeof( temp ), 0 );
  390. if ( bytesReceived <= 0 )
  391. return false;
  392. buf.Put( ( const void * )temp, (u32)bytesReceived );
  393. totalReceived = buf.TellPut();
  394. if ( totalReceived >= bytesExpected )
  395. break;
  396. }
  397. return true;
  398. }
  399. void CWin32UploadBugReport::AddState( uint StateIndex, pfnProtocolStateHandler handler )
  400. {
  401. FSMState_t newState( StateIndex, handler );
  402. m_States.AddToTail( newState );
  403. }
  404. EBugReportUploadStatus CWin32UploadBugReport::Upload( CUtlBuffer& buf )
  405. {
  406. UpdateProgress( m_rBugReportParameters, "Commencing bug report upload connection." );
  407. EBugReportUploadStatus result = eBugReportUploadSucceeded;
  408. // Run the state machine
  409. while ( 1 )
  410. {
  411. Assert( m_States[ m_uCurrentState ].first == m_uCurrentState );
  412. pfnProtocolStateHandler handler = m_States[ m_uCurrentState ].second;
  413. if ( !(this->*handler)( result, buf ) )
  414. {
  415. return result;
  416. }
  417. }
  418. }
  419. void CWin32UploadBugReport::SetNextState( uint StateIndex )
  420. {
  421. Assert( StateIndex > m_uCurrentState );
  422. m_uCurrentState = StateIndex;
  423. }
  424. bool CWin32UploadBugReport::CreateTCPSocket( EBugReportUploadStatus& status, CUtlBuffer& /*buf*/ )
  425. {
  426. UpdateProgress( m_rBugReportParameters, "Creating bug report upload socket." );
  427. m_SocketTCP = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
  428. if ( m_SocketTCP == (uint)SOCKET_ERROR )
  429. {
  430. UpdateProgress( m_rBugReportParameters, "Socket creation failed." );
  431. status = eBugReportUploadFailed;
  432. return false;
  433. }
  434. SetNextState( eConnectToHarvesterServer );
  435. return true;
  436. }
  437. bool CWin32UploadBugReport::ConnectToHarvesterServer( EBugReportUploadStatus& status, CUtlBuffer& /*buf*/ )
  438. {
  439. UpdateProgress( m_rBugReportParameters, "Connecting to bug report harvesting server." );
  440. if ( connect( m_SocketTCP, (const sockaddr *)&m_HarvesterSockAddr, sizeof( m_HarvesterSockAddr ) ) == SOCKET_ERROR )
  441. {
  442. UpdateProgress( m_rBugReportParameters, "Connection failed." );
  443. status = eBugReportConnectToCSERServerFailed;
  444. return false;
  445. }
  446. SetNextState( eSendProtocolVersion );
  447. return true;
  448. }
  449. bool CWin32UploadBugReport::SendProtocolVersion( EBugReportUploadStatus& status, CUtlBuffer& buf )
  450. {
  451. UpdateProgress( m_rBugReportParameters, "Sending bug report harvester protocol info." );
  452. buf.SetBigEndian( true );
  453. // Send protocol version
  454. buf.Purge();
  455. buf.PutInt( cuCurrentProtocolVersion );
  456. if ( send( m_SocketTCP, (const char *)buf.Base(), (int)buf.TellPut(), 0 ) == SOCKET_ERROR )
  457. {
  458. UpdateProgress( m_rBugReportParameters, "Send failed." );
  459. status = eBugReportUploadFailed;
  460. return false;
  461. }
  462. SetNextState( eReceiveProtocolOkay );
  463. return true;
  464. }
  465. bool CWin32UploadBugReport::ReceiveProtocolOkay( EBugReportUploadStatus& status, CUtlBuffer& buf )
  466. {
  467. UpdateProgress( m_rBugReportParameters, "Receiving harvesting protocol acknowledgement." );
  468. buf.Purge();
  469. // Now receive the protocol is acceptable token from the server
  470. if ( !DoBlockingReceive( 1, buf ) )
  471. {
  472. UpdateProgress( m_rBugReportParameters, "Didn't receive protocol failure data." );
  473. status = eBugReportUploadFailed;
  474. return false;
  475. }
  476. bool protocolokay = buf.GetChar() ? true : false;
  477. if ( !protocolokay )
  478. {
  479. UpdateProgress( m_rBugReportParameters, "Server rejected protocol." );
  480. status = eBugReportUploadFailed;
  481. return false;
  482. }
  483. UpdateProgress( m_rBugReportParameters, "Protocol OK." );
  484. SetNextState( eSendUploadCommand );
  485. return true;
  486. }
  487. bool CWin32UploadBugReport::SendUploadCommand( EBugReportUploadStatus& status, CUtlBuffer& buf )
  488. {
  489. UpdateProgress( m_rBugReportParameters, "Sending harvesting protocol upload request." );
  490. // Send upload command
  491. buf.Purge();
  492. NetworkMessageLengthPrefix_t messageSize
  493. (
  494. sizeof( Command_t )
  495. + sizeof( ContextID_t )
  496. + sizeof( HarvestFileCommand::FileSize_t )
  497. + sizeof( HarvestFileCommand::SendMethod_t )
  498. + sizeof( HarvestFileCommand::FileSize_t )
  499. );
  500. // Prefix the length to the command
  501. buf.PutInt( (int)messageSize );
  502. buf.PutChar( Commands::cuSendBugReport );
  503. buf.PutInt( (int)m_ContextID );
  504. buf.PutInt( (int)m_rBugReportParameters.m_uAttachmentFileSize );
  505. buf.PutInt( static_cast<HarvestFileCommand::SendMethod_t>( eSendMethodWholeRawFileNoBlocks ) );
  506. buf.PutInt( static_cast<HarvestFileCommand::FileSize_t>( 0 ) );
  507. // Send command to server
  508. if ( send( m_SocketTCP, (const char *)buf.Base(), (int)buf.TellPut(), 0 ) == SOCKET_ERROR )
  509. {
  510. UpdateProgress( m_rBugReportParameters, "Send failed." );
  511. status = eBugReportUploadFailed;
  512. return false;
  513. }
  514. SetNextState( eReceiveOKToSendFile );
  515. return true;
  516. }
  517. bool CWin32UploadBugReport::ReceiveOKToSendFile( EBugReportUploadStatus& status, CUtlBuffer& buf )
  518. {
  519. UpdateProgress( m_rBugReportParameters, "Receive bug report harvesting protocol upload permissible." );
  520. // Now receive the protocol is acceptable token from the server
  521. if ( !DoBlockingReceive( 1, buf ) )
  522. {
  523. UpdateProgress( m_rBugReportParameters, "Receive failed." );
  524. status = eBugReportUploadFailed;
  525. return false;
  526. }
  527. bool dosend = false;
  528. CommandResponse_t cmd = (CommandResponse_t)buf.GetChar();
  529. switch ( cmd )
  530. {
  531. case HarvestFileCommand::cuOkToSendFile:
  532. {
  533. dosend = true;
  534. }
  535. break;
  536. case HarvestFileCommand::cuFileTooBig:
  537. case HarvestFileCommand::cuInvalidSendMethod:
  538. case HarvestFileCommand::cuInvalidMaxCompressedChunkSize:
  539. case HarvestFileCommand::cuInvalidBugReportContext:
  540. default:
  541. break;
  542. }
  543. if ( !dosend )
  544. {
  545. UpdateProgress( m_rBugReportParameters, "Server rejected upload command." );
  546. status = eBugReportUploadFailed;
  547. return false;
  548. }
  549. SetNextState( eSendWholeFile );
  550. return true;
  551. }
  552. bool CWin32UploadBugReport::SendWholeFile( EBugReportUploadStatus& status, CUtlBuffer& /*buf*/ )
  553. {
  554. UpdateProgress( m_rBugReportParameters, "Uploading bug report data." );
  555. // Send to server
  556. char *filebuf = NULL;
  557. size_t sizeactual = g_pFileSystem->Size( m_rBugReportParameters.m_sAttachmentFile );
  558. if ( sizeactual > 0 )
  559. {
  560. filebuf = new char[ sizeactual + 1 ];
  561. if ( filebuf )
  562. {
  563. FileHandle_t fh;
  564. fh = g_pFileSystem->Open( m_rBugReportParameters.m_sAttachmentFile, "rb" );
  565. if ( FILESYSTEM_INVALID_HANDLE != fh )
  566. {
  567. g_pFileSystem->Read( (void *)filebuf, sizeactual, fh );
  568. g_pFileSystem->Close( fh );
  569. }
  570. filebuf[ sizeactual ] = 0;
  571. }
  572. }
  573. if ( !sizeactual || !filebuf )
  574. {
  575. UpdateProgress( m_rBugReportParameters, "bug .zip file size zero or unable to allocate memory for file." );
  576. status = eBugReportUploadFailed;
  577. if ( filebuf )
  578. {
  579. delete[] filebuf;
  580. }
  581. return false;
  582. }
  583. // Send to server
  584. bool bret = true;
  585. if ( send( m_SocketTCP, filebuf, (int)sizeactual, 0 ) == SOCKET_ERROR )
  586. {
  587. bret = false;
  588. UpdateProgress( m_rBugReportParameters, "Send failed." );
  589. status = eBugReportUploadFailed;
  590. }
  591. else
  592. {
  593. SetNextState( eReceiveFileUploadSuccess );
  594. }
  595. delete[] filebuf;
  596. return bret;
  597. }
  598. bool CWin32UploadBugReport::ReceiveFileUploadSuccess( EBugReportUploadStatus& status, CUtlBuffer& buf )
  599. {
  600. UpdateProgress( m_rBugReportParameters, "Receiving bug report upload success/fail message." );
  601. // Now receive the protocol is acceptable token from the server
  602. if ( !DoBlockingReceive( 1, buf ) )
  603. {
  604. UpdateProgress( m_rBugReportParameters, "Receive failed." );
  605. status = eBugReportUploadFailed;
  606. return false;
  607. }
  608. bool success = buf.GetChar() == 1 ? true : false;
  609. if ( !success )
  610. {
  611. UpdateProgress( m_rBugReportParameters, "Upload failed." );
  612. status = eBugReportUploadFailed;
  613. return false;
  614. }
  615. UpdateProgress( m_rBugReportParameters, "Upload OK." );
  616. SetNextState( eSendGracefulClose );
  617. return true;
  618. }
  619. bool CWin32UploadBugReport::SendGracefulClose( EBugReportUploadStatus& status, CUtlBuffer& buf )
  620. {
  621. UpdateProgress( m_rBugReportParameters, "Closing connection to server." );
  622. // Now send disconnect command
  623. buf.Purge();
  624. size_t messageSize = sizeof( Command_t );
  625. buf.PutInt( (int)messageSize );
  626. buf.PutChar( Commands::cuGracefulClose );
  627. if ( send( m_SocketTCP, (const char *)buf.Base(), (int)buf.TellPut(), 0 ) == SOCKET_ERROR )
  628. {
  629. UpdateProgress( m_rBugReportParameters, "Send failed." );
  630. status = eBugReportUploadFailed;
  631. return false;
  632. }
  633. SetNextState( eCloseTCPSocket );
  634. return true;
  635. }
  636. bool CWin32UploadBugReport::CloseTCPSocket( EBugReportUploadStatus& status, CUtlBuffer& /*buf*/ )
  637. {
  638. UpdateProgress( m_rBugReportParameters, "Closing socket, upload succeeded." );
  639. closesocket( m_SocketTCP );//lint !e534
  640. m_SocketTCP = 0;
  641. status = eBugReportUploadSucceeded;
  642. // NOTE: Returning false here ends the state machine!!!
  643. return false;
  644. }
  645. EBugReportUploadStatus Win32UploadBugReportBlocking
  646. (
  647. const TBugReportParameters & rBugReportParameters
  648. )
  649. {
  650. EBugReportUploadStatus status = eBugReportUploadFailed;
  651. CUtlBuffer buf( 2048 );
  652. UpdateProgress( rBugReportParameters, "Creating initial report." );
  653. buf.SetBigEndian( false );
  654. buf.Purge();
  655. buf.PutChar( C2M_BUGREPORT );
  656. buf.PutChar( '\n' );
  657. buf.PutChar( C2M_BUGREPORT_PROTOCOL_VERSION );
  658. // See CSERServerProtocol.h for format
  659. // encryption object
  660. IceKey cipher(1); /* medium encryption level */
  661. unsigned char ucEncryptionKey[8] = { 200,145,10,149,195,190,108,243 };
  662. cipher.set( ucEncryptionKey );
  663. CUtlBuffer encrypted( 2000 );
  664. u8 corruption_identifier = 0x01;
  665. encrypted.PutChar( corruption_identifier );
  666. encrypted.PutInt( rBugReportParameters.m_uEngineBuildNumber ); // build_identifier
  667. encrypted.PutString( rBugReportParameters.m_sExecutableName );
  668. encrypted.PutString( rBugReportParameters.m_sGameDirectory );
  669. encrypted.PutString( rBugReportParameters.m_sMapName );
  670. encrypted.PutInt( rBugReportParameters.m_uRAM ); // ram mb
  671. encrypted.PutInt( rBugReportParameters.m_uCPU ); // cpu mhz
  672. encrypted.PutString( rBugReportParameters.m_sProcessor );
  673. encrypted.PutInt( rBugReportParameters.m_uDXVersionHigh ); // driver version high part
  674. encrypted.PutInt( rBugReportParameters.m_uDXVersionLow ); // driver version low part
  675. encrypted.PutInt( rBugReportParameters.m_uDXVendorId ); // dxvendor id
  676. encrypted.PutInt( rBugReportParameters.m_uDXDeviceId ); // dxdevice id
  677. encrypted.PutString( rBugReportParameters.m_sOSVersion );
  678. encrypted.PutInt( rBugReportParameters.m_uAttachmentFileSize );
  679. // protocol version 2 stuff
  680. {
  681. encrypted.PutString( rBugReportParameters.m_sReportType );
  682. encrypted.PutString( rBugReportParameters.m_sEmail );
  683. encrypted.PutString( rBugReportParameters.m_sAccountName );
  684. }
  685. // protocol version 3 stuff
  686. {
  687. encrypted.Put( &rBugReportParameters.m_userid, sizeof( rBugReportParameters.m_userid ) );
  688. }
  689. encrypted.PutString( rBugReportParameters.m_sTitle );
  690. int bodylen = Q_strlen( rBugReportParameters.m_sBody ) + 1;
  691. encrypted.PutInt( bodylen );
  692. encrypted.Put( rBugReportParameters.m_sBody, bodylen );
  693. while ( encrypted.TellPut() % 8 )
  694. {
  695. encrypted.PutChar( 0 );
  696. }
  697. EncryptBuffer( cipher, (unsigned char *)encrypted.Base(), encrypted.TellPut() );
  698. buf.PutShort( (int)encrypted.TellPut() );
  699. buf.Put( (unsigned char *)encrypted.Base(), encrypted.TellPut() );
  700. CBlockingUDPSocket bcs;
  701. if ( !bcs.IsValid() )
  702. {
  703. return eBugReportUploadFailed;
  704. }
  705. struct sockaddr_in sa;
  706. rBugReportParameters.m_ipCSERServer.ToSockadr( (struct sockaddr *)&sa );
  707. UpdateProgress( rBugReportParameters, "Sending bug report to server." );
  708. bcs.SendSocketMessage( sa, (const u8 *)buf.Base(), buf.TellPut() ); //lint !e534
  709. UpdateProgress( rBugReportParameters, "Waiting for response." );
  710. if ( bcs.WaitForMessage( 2.0f ) )
  711. {
  712. UpdateProgress( rBugReportParameters, "Received response." );
  713. struct sockaddr_in replyaddress;
  714. buf.EnsureCapacity( 2048 );
  715. uint bytesReceived = bcs.ReceiveSocketMessage( &replyaddress, (u8 *)buf.Base(), 2048 );
  716. if ( bytesReceived > 0 )
  717. {
  718. // Fixup actual size
  719. buf.SeekPut( CUtlBuffer::SEEK_HEAD, bytesReceived );
  720. UpdateProgress( rBugReportParameters, "Checking response." );
  721. // Parse out data
  722. u8 msgtype = (u8)buf.GetChar();
  723. if ( M2C_ACKBUGREPORT != msgtype )
  724. {
  725. UpdateProgress( rBugReportParameters, "Request denied, invalid message type." );
  726. return eBugReportSendingBugReportHeaderFailed;
  727. }
  728. bool validProtocol = (u8)buf.GetChar() == 1 ? true : false;
  729. if ( !validProtocol )
  730. {
  731. UpdateProgress( rBugReportParameters, "Request denied, invalid message protocol." );
  732. return eBugReportSendingBugReportHeaderFailed;
  733. }
  734. u8 disposition = (u8)buf.GetChar();
  735. if ( BR_REQEST_FILES != disposition )
  736. {
  737. // Server doesn't want a bug report, oh well
  738. if ( rBugReportParameters.m_uAttachmentFileSize > 0 )
  739. {
  740. UpdateProgress( rBugReportParameters, "Bug report accepted, attachment rejected (server too busy)" );
  741. }
  742. else
  743. {
  744. UpdateProgress( rBugReportParameters, "Bug report accepted." );
  745. }
  746. return eBugReportUploadSucceeded;
  747. }
  748. // Read in the bug report info parameters
  749. u32 harvester_ip = (u32)buf.GetInt();
  750. u16 harvester_port = (u16)buf.GetShort();
  751. u32 dumpcontext = (u32)buf.GetInt();
  752. sockaddr_in adr;
  753. adr.sin_family = AF_INET;
  754. adr.sin_port = htons( harvester_port );
  755. #ifdef WIN32
  756. adr.sin_addr.S_un.S_addr = harvester_ip;
  757. #else
  758. adr.sin_addr.s_addr = harvester_ip;
  759. #endif
  760. netadr_t BugReportHarvesterFSMIPAddress;
  761. BugReportHarvesterFSMIPAddress.SetFromSockadr( (struct sockaddr *)&adr );
  762. UpdateProgress( rBugReportParameters, "Server requested bug report upload." );
  763. // Keep using the same scratch buffer for messaging
  764. CWin32UploadBugReport uploader( BugReportHarvesterFSMIPAddress, rBugReportParameters, dumpcontext );
  765. status = uploader.Upload( buf );
  766. }
  767. }
  768. else
  769. {
  770. UpdateProgress( rBugReportParameters, "No response from server." );
  771. }
  772. return status;
  773. }