summaryrefslogtreecommitdiff
path: root/utils/bugreporter_public
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/bugreporter_public
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'utils/bugreporter_public')
-rw-r--r--utils/bugreporter_public/bugreporter_public.cpp745
-rw-r--r--utils/bugreporter_public/bugreporter_public.vpc65
-rw-r--r--utils/bugreporter_public/bugreporter_upload.cpp969
3 files changed, 1779 insertions, 0 deletions
diff --git a/utils/bugreporter_public/bugreporter_public.cpp b/utils/bugreporter_public/bugreporter_public.cpp
new file mode 100644
index 0000000..87ecb27
--- /dev/null
+++ b/utils/bugreporter_public/bugreporter_public.cpp
@@ -0,0 +1,745 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+#define PROTECTED_THINGS_DISABLE
+#undef PROTECT_FILEIO_FUNCTIONS
+#undef fopen
+#include "winlite.h"
+#include "basetypes.h"
+
+#include "utlvector.h"
+#include "utlsymbol.h"
+#include "utldict.h"
+#include "utlbuffer.h"
+#include "steamcommon.h"
+
+#include "bugreporter/bugreporter.h"
+#include "filesystem_tools.h"
+#include "KeyValues.h"
+#include "netadr.h"
+#include "steam/steamclientpublic.h"
+
+bool UploadBugReport(
+ const netadr_t& cserIP,
+ const CSteamID& userid,
+ int build,
+ char const *title,
+ char const *body,
+ char const *exename,
+ char const *gamedir,
+ char const *mapname,
+ char const *reporttype,
+ char const *email,
+ char const *accountname,
+ int ram,
+ int cpu,
+ char const *processor,
+ unsigned int high,
+ unsigned int low,
+ unsigned int vendor,
+ unsigned int device,
+ char const *osversion,
+ char const *attachedfile,
+ unsigned int attachedfilesize
+);
+
+IBaseFileSystem *g_pFileSystem = NULL;
+
+class CBug
+{
+public:
+ CBug()
+ {
+ Clear();
+ }
+
+ void Clear()
+ {
+ Q_memset( title, 0, sizeof( title ) );
+ Q_memset( desc, 0, sizeof( desc ) );
+ Q_memset( submitter, 0, sizeof( submitter ) );
+ Q_memset( owner, 0, sizeof( owner ) );
+ Q_memset( severity, 0, sizeof( severity ) );
+ Q_memset( priority, 0, sizeof( priority ) );
+ Q_memset( area, 0, sizeof( area ) );
+ Q_memset( mapnumber, 0, sizeof( mapnumber) );
+ Q_memset( reporttype, 0, sizeof( reporttype ) );
+ Q_memset( level, 0, sizeof( level ) );
+ Q_memset( build, 0, sizeof( build ) );
+ Q_memset( position, 0, sizeof( position ) );
+ Q_memset( orientation, 0, sizeof( orientation ) );
+ Q_memset( screenshot_unc, 0, sizeof( screenshot_unc ) );
+ Q_memset( savegame_unc, 0, sizeof( savegame_unc ) );
+ Q_memset( bsp_unc, 0, sizeof( bsp_unc ) );
+ Q_memset( vmf_unc, 0, sizeof( vmf_unc ) );
+ Q_memset( driverinfo, 0, sizeof( driverinfo ) );
+ Q_memset( misc, 0, sizeof( misc ) );
+ Q_memset( zip, 0, sizeof( zip ) );
+
+ Q_memset( exename, 0, sizeof( exename ) );
+ Q_memset( gamedir, 0, sizeof( gamedir ) );
+ ram = 0;
+ cpu = 0;
+ Q_memset( processor, 0, sizeof( processor ) );
+ dxversionhigh = 0;
+ dxversionlow = 0;
+ dxvendor = 0;
+ dxdevice = 0;
+ Q_memset( osversion, 0, sizeof( osversion ) );
+
+ includedfiles.Purge();
+ }
+
+ char title[ 256 ];
+ char desc[ 8192 ];
+ char owner[ 256 ];
+ char submitter[ 256 ];
+ char severity[ 256 ];
+ char priority[ 256 ];
+ char area[ 256 ];
+ char mapnumber[ 256 ];
+ char reporttype[ 256 ];
+ char level[ 256 ];
+ char build[ 256 ];
+ char position[ 256 ];
+ char orientation[ 256 ];
+ char screenshot_unc[ 256 ];
+ char savegame_unc[ 256 ];
+ char bsp_unc[ 256 ];
+ char vmf_unc[ 256 ];
+ char driverinfo[ 2048 ];
+ char misc[ 1024 ];
+
+ char exename[ 256 ];
+ char gamedir[ 256 ];
+ unsigned int ram;
+ unsigned int cpu;
+ char processor[ 256 ];
+ unsigned int dxversionhigh;
+ unsigned int dxversionlow;
+ unsigned int dxvendor;
+ unsigned int dxdevice;
+ char osversion[ 256 ];
+
+ char zip[ 256 ];
+
+ struct incfile
+ {
+ char name[ 256 ];
+ };
+
+ CUtlVector< incfile > includedfiles;
+};
+
+class CBugReporter : public IBugReporter
+{
+public:
+
+ CBugReporter();
+ virtual ~CBugReporter();
+
+ // Initialize and login with default username/password for this computer (from resource/bugreporter.res)
+ virtual bool Init( CreateInterfaceFn engineFactory );
+ virtual void Shutdown();
+
+ virtual bool IsPublicUI() { return true; }
+
+ virtual char const *GetUserName();
+ virtual char const *GetUserName_Display();
+
+ virtual int GetNameCount();
+ virtual char const *GetName( int index );
+
+ virtual int GetDisplayNameCount();
+ virtual char const *GetDisplayName( int index );
+
+ virtual char const *GetDisplayNameForUserName( char const *username );
+ virtual char const *GetUserNameForDisplayName( char const *display );
+
+ virtual int GetSeverityCount();
+ virtual char const *GetSeverity( int index );
+
+ virtual int GetPriorityCount();
+ virtual char const *GetPriority( int index );
+
+ virtual int GetAreaCount();
+ virtual char const *GetArea( int index );
+
+ virtual int GetAreaMapCount();
+ virtual char const *GetAreaMap( int index );
+
+ virtual int GetMapNumberCount();
+ virtual char const *GetMapNumber( int index );
+
+ virtual int GetReportTypeCount();
+ virtual char const *GetReportType( int index );
+
+ virtual char const *GetRepositoryURL( void ) { return NULL; }
+ virtual char const *GetSubmissionURL( void ) { return NULL; }
+
+ virtual int GetLevelCount(int area) { return 0; }
+ virtual char const *GetLevel(int area, int index ) { return ""; }
+
+// Submission API
+ virtual void StartNewBugReport();
+ virtual void CancelNewBugReport();
+ virtual bool CommitBugReport( int& bugSubmissionId );
+
+ virtual void SetTitle( char const *title );
+ virtual void SetDescription( char const *description );
+
+ // NULL for current user
+ virtual void SetSubmitter( char const *username = 0 );
+ virtual void SetOwner( char const *username );
+ virtual void SetSeverity( char const *severity );
+ virtual void SetPriority( char const *priority );
+ virtual void SetArea( char const *area );
+ virtual void SetMapNumber ( char const *mapnumber );
+ virtual void SetReportType( char const *reporttype );
+
+ virtual void SetLevel( char const *levelnamne );
+ virtual void SetPosition( char const *position );
+ virtual void SetOrientation( char const *pitch_yaw_roll );
+ virtual void SetBuildNumber( char const *build_num );
+
+ virtual void SetScreenShot( char const *screenshot_unc_address );
+ virtual void SetSaveGame( char const *savegame_unc_address );
+
+ virtual void SetBSPName( char const *bsp_unc_address );
+ virtual void SetVMFName( char const *vmf_unc_address );
+
+ virtual void AddIncludedFile( char const *filename );
+ virtual void ResetIncludedFiles();
+
+ virtual void SetDriverInfo( char const *info );
+
+ virtual void SetZipAttachmentName( char const *zipfilename );
+
+ virtual void SetMiscInfo( char const *info );
+
+ virtual void SetCSERAddress( const struct netadr_s& adr );
+ virtual void SetExeName( char const *exename );
+ virtual void SetGameDirectory( char const *gamedir );
+ virtual void SetRAM( int ram );
+ virtual void SetCPU( int cpu );
+ virtual void SetProcessor( char const *processor );
+ virtual void SetDXVersion( unsigned int high, unsigned int low, unsigned int vendor, unsigned int device );
+ virtual void SetOSVersion( char const *osversion );
+ virtual void SetSteamUserID( void *steamid, int idsize );
+
+private:
+
+ void SubstituteBugId( int bugid, char *out, int outlen, CUtlBuffer& src );
+
+ CUtlSymbolTable m_BugStrings;
+
+ CUtlVector< CUtlSymbol > m_Severity;
+ CUtlVector< CUtlSymbol > m_Area;
+ CUtlVector< CUtlSymbol > m_MapNumber;
+ CUtlVector< CUtlSymbol > m_ReportType;
+
+ CUtlSymbol m_UserName;
+
+ CBug *m_pBug;
+ netadr_t m_cserIP;
+ CSteamID m_SteamID;
+};
+
+CBugReporter::CBugReporter()
+{
+ Q_memset( &m_cserIP, 0, sizeof( m_cserIP ) );
+ m_pBug = NULL;
+
+ m_Severity.AddToTail( m_BugStrings.AddString( "Zero" ) );
+ m_Severity.AddToTail( m_BugStrings.AddString( "Low" ) );
+ m_Severity.AddToTail( m_BugStrings.AddString( "Medium" ) );
+ m_Severity.AddToTail( m_BugStrings.AddString( "High" ) );
+ m_Severity.AddToTail( m_BugStrings.AddString( "Showstopper" ) );
+
+
+ m_ReportType.AddToTail( m_BugStrings.AddString( "<<Choose Item>>" ) );
+ m_ReportType.AddToTail( m_BugStrings.AddString( "Video / Display Problems" ) );
+ m_ReportType.AddToTail( m_BugStrings.AddString( "Network / Connectivity Problems" ) );
+ m_ReportType.AddToTail( m_BugStrings.AddString( "Download / Installation Problems" ) );
+ m_ReportType.AddToTail( m_BugStrings.AddString( "In-game Crash" ) );
+ m_ReportType.AddToTail( m_BugStrings.AddString( "Game play / Strategy Problems" ) );
+ m_ReportType.AddToTail( m_BugStrings.AddString( "Steam Problems" ) );
+ m_ReportType.AddToTail( m_BugStrings.AddString( "Unlisted Bug" ) );
+ m_ReportType.AddToTail( m_BugStrings.AddString( "Feature Request / Suggestion" ) );
+}
+
+CBugReporter::~CBugReporter()
+{
+ m_BugStrings.RemoveAll();
+ m_Severity.Purge();
+ m_Area.Purge();
+ m_MapNumber.Purge();
+ m_ReportType.Purge();
+
+ delete m_pBug;
+}
+//-----------------------------------------------------------------------------
+// Purpose: Initialize and login with default username/password for this computer (from resource/bugreporter.res)
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CBugReporter::Init( CreateInterfaceFn engineFactory )
+{
+ g_pFileSystem = (IFileSystem *)engineFactory( FILESYSTEM_INTERFACE_VERSION, NULL );
+ if ( !g_pFileSystem )
+ {
+ AssertMsg( 0, "Failed to create/get IFileSystem" );
+ return false;
+ }
+ return true;
+}
+
+void CBugReporter::Shutdown()
+{
+}
+
+char const *CBugReporter::GetUserName()
+{
+ return m_UserName.String();
+}
+
+char const *CBugReporter::GetUserName_Display()
+{
+ return GetUserName();
+}
+
+int CBugReporter::GetNameCount()
+{
+ return 1;
+}
+
+char const *CBugReporter::GetName( int index )
+{
+ if ( index < 0 || index >= 1 )
+ return "<<Invalid>>";
+
+ return GetUserName();
+}
+
+int CBugReporter::GetDisplayNameCount()
+{
+ return 1;
+}
+
+char const *CBugReporter::GetDisplayName( int index )
+{
+ if ( index < 0 || index >= 1 )
+ return "<<Invalid>>";
+
+ return GetUserName();
+}
+
+char const *CBugReporter::GetDisplayNameForUserName( char const *username )
+{
+ return username;
+}
+
+char const *CBugReporter::GetUserNameForDisplayName( char const *display )
+{
+ return display;
+}
+
+int CBugReporter::GetSeverityCount()
+{
+ return m_Severity.Count() ;
+}
+
+char const *CBugReporter::GetSeverity( int index )
+{
+ if ( index < 0 || index >= m_Severity.Count() )
+ return "<<Invalid>>";
+
+ return m_BugStrings.String( m_Severity[ index ] );
+}
+
+int CBugReporter::GetPriorityCount()
+{
+ return 0;
+}
+
+char const *CBugReporter::GetPriority( int index )
+{
+ return "<<Invalid>>";
+}
+
+int CBugReporter::GetAreaCount()
+{
+ return 0;
+}
+
+char const *CBugReporter::GetArea( int index )
+{
+ return "<<Invalid>>";
+}
+
+int CBugReporter::GetAreaMapCount()
+{
+ return 0;
+}
+
+char const *CBugReporter::GetAreaMap( int index )
+{
+ return "<<Invalid>>";
+}
+
+int CBugReporter::GetMapNumberCount()
+{
+ return 0;
+}
+
+char const *CBugReporter::GetMapNumber( int index )
+{
+ return "<<Invalid>>";
+}
+
+int CBugReporter::GetReportTypeCount()
+{
+ return m_ReportType.Count();
+}
+
+char const *CBugReporter::GetReportType( int index )
+{
+ if ( index < 0 || index >= m_ReportType.Count() )
+ return "<<Invalid>>";
+
+ return m_BugStrings.String( m_ReportType[ index ] );
+}
+
+void CBugReporter::StartNewBugReport()
+{
+ if ( !m_pBug )
+ {
+ m_pBug = new CBug();
+ }
+ else
+ {
+ m_pBug->Clear();
+ }
+}
+
+void CBugReporter::CancelNewBugReport()
+{
+ if ( !m_pBug )
+ return;
+
+ m_pBug->Clear();
+}
+
+void CBugReporter::SubstituteBugId( int bugid, char *out, int outlen, CUtlBuffer& src )
+{
+ out[ 0 ] = 0;
+
+ char *dest = out;
+
+ src.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
+
+ char const *replace = "\\BugId\\";
+ int replace_len = Q_strlen( replace );
+
+ for ( int pos = 0; pos <= src.TellPut() && ( ( dest - out ) < outlen ); )
+ {
+ char const *str = ( char const * )src.PeekGet( pos );
+ if ( !Q_strnicmp( str, replace, replace_len ) )
+ {
+ *dest++ = '\\';
+
+ char num[ 32 ];
+ Q_snprintf( num, sizeof( num ), "%i", bugid );
+ char *pnum = num;
+ while ( *pnum )
+ {
+ *dest++ = *pnum++;
+ }
+
+ *dest++ = '\\';
+ pos += replace_len;
+ continue;
+ }
+
+ *dest++ = *str;
+ ++pos;
+ }
+ *dest = 0;
+}
+
+bool CBugReporter::CommitBugReport( int& bugSubmissionId )
+{
+ bugSubmissionId = -1;
+
+ if ( !m_pBug )
+ return false;
+
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+
+ buf.Printf( "%s\n\n", m_pBug->desc );
+
+ buf.Printf( "level: %s\nbuild: %s\nposition: setpos %s; setang %s\n",
+ m_pBug->level,
+ m_pBug->build,
+ m_pBug->position,
+ m_pBug->orientation );
+
+ if ( m_pBug->screenshot_unc[ 0 ] )
+ {
+ buf.Printf( "screenshot: %s\n", m_pBug->screenshot_unc );
+ }
+ if ( m_pBug->savegame_unc[ 0 ] )
+ {
+ buf.Printf( "savegame: %s\n", m_pBug->savegame_unc );
+ }
+ /*
+ if ( m_pBug->bsp_unc[ 0 ] )
+ {
+ buf.Printf( "bsp: %s\n", m_pBug->bsp_unc );
+ }
+ if ( m_pBug->vmf_unc[ 0 ] )
+ {
+ buf.Printf( "vmf: %s\n", m_pBug->vmf_unc );
+ }
+ if ( m_pBug->includedfiles.Count() > 0 )
+ {
+ int c = m_pBug->includedfiles.Count();
+ for ( int i = 0 ; i < c; ++i )
+ {
+ buf.Printf( "include: %s\n", m_pBug->includedfiles[ i ].name );
+ }
+ }
+ */
+ if ( m_pBug->driverinfo[ 0 ] )
+ {
+ buf.Printf( "%s\n", m_pBug->driverinfo );
+ }
+ if ( m_pBug->misc[ 0 ] )
+ {
+ buf.Printf( "%s\n", m_pBug->misc );
+ }
+
+ buf.PutChar( 0 );
+
+ // Store desc
+
+ int bugId = 0;
+
+ bugSubmissionId = (int)bugId;
+
+ int attachedfilesize = ( m_pBug->zip[ 0 ] == 0 ) ? 0 : g_pFileSystem->Size( m_pBug->zip );
+
+ if ( !UploadBugReport(
+ m_cserIP,
+ m_SteamID,
+ atoi( m_pBug->build ),
+ m_pBug->title,
+ (char const *)buf.Base(),
+ m_pBug->exename,
+ m_pBug->gamedir,
+ m_pBug->level,
+ m_pBug->reporttype,
+ m_pBug->owner,
+ m_pBug->submitter,
+ m_pBug->ram,
+ m_pBug->cpu,
+ m_pBug->processor,
+ m_pBug->dxversionhigh,
+ m_pBug->dxversionlow,
+ m_pBug->dxvendor,
+ m_pBug->dxdevice,
+ m_pBug->osversion,
+ m_pBug->zip,
+ attachedfilesize
+ ) )
+ {
+ Msg( "Unable to upload bug...\n" );
+ }
+
+ m_pBug->Clear();
+
+ return true;
+}
+
+void CBugReporter::SetTitle( char const *title )
+{
+ Assert( m_pBug );
+ Q_strncpy( m_pBug->title, title, sizeof( m_pBug->title ) );
+}
+
+void CBugReporter::SetDescription( char const *description )
+{
+ Assert( m_pBug );
+ Q_strncpy( m_pBug->desc, description, sizeof( m_pBug->desc ) );
+}
+
+void CBugReporter::SetSubmitter( char const *username /*= 0*/ )
+{
+ m_UserName = username;
+ /*
+ if ( !username )
+ {
+ username = GetUserName();
+ }
+ */
+
+ Assert( m_pBug );
+ Q_strncpy( m_pBug->submitter, username ? username : "", sizeof( m_pBug->submitter ) );
+}
+
+void CBugReporter::SetOwner( char const *username )
+{
+ Q_strncpy( m_pBug->owner, username, sizeof( m_pBug->owner ) );
+}
+
+void CBugReporter::SetSeverity( char const *severity )
+{
+}
+
+void CBugReporter::SetPriority( char const *priority )
+{
+}
+
+void CBugReporter::SetArea( char const *area )
+{
+}
+
+void CBugReporter::SetMapNumber( char const *mapnumber )
+{
+}
+
+void CBugReporter::SetReportType( char const *reporttype )
+{
+ Q_strncpy( m_pBug->reporttype, reporttype, sizeof( m_pBug->reporttype ) );
+}
+
+void CBugReporter::SetLevel( char const *levelnamne )
+{
+ Assert( m_pBug );
+ Q_strncpy( m_pBug->level, levelnamne, sizeof( m_pBug->level ) );
+}
+
+void CBugReporter::SetDriverInfo( char const *info )
+{
+ Assert( m_pBug );
+ Q_strncpy( m_pBug->driverinfo, info, sizeof( m_pBug->driverinfo ) );
+}
+
+void CBugReporter::SetZipAttachmentName( char const *zipfilename )
+{
+ Assert( m_pBug );
+
+ Q_strncpy( m_pBug->zip, zipfilename, sizeof( m_pBug->zip ) );
+}
+
+void CBugReporter::SetMiscInfo( char const *info )
+{
+ Assert( m_pBug );
+ Q_strncpy( m_pBug->misc, info, sizeof( m_pBug->misc ) );
+}
+
+void CBugReporter::SetPosition( char const *position )
+{
+ Assert( m_pBug );
+ Q_strncpy( m_pBug->position, position, sizeof( m_pBug->position ) );
+}
+
+void CBugReporter::SetOrientation( char const *pitch_yaw_roll )
+{
+ Assert( m_pBug );
+ Q_strncpy( m_pBug->orientation, pitch_yaw_roll, sizeof( m_pBug->orientation ) );
+}
+
+void CBugReporter::SetBuildNumber( char const *build_num )
+{
+ Assert( m_pBug );
+ Q_strncpy( m_pBug->build, build_num, sizeof( m_pBug->build ) );
+}
+
+void CBugReporter::SetScreenShot( char const *screenshot_unc_address )
+{
+ Assert( m_pBug );
+ Q_strncpy( m_pBug->screenshot_unc, screenshot_unc_address, sizeof( m_pBug->screenshot_unc ) );
+}
+
+void CBugReporter::SetSaveGame( char const *savegame_unc_address )
+{
+ Assert( m_pBug );
+ Q_strncpy( m_pBug->savegame_unc, savegame_unc_address, sizeof( m_pBug->savegame_unc ) );
+}
+
+void CBugReporter::SetBSPName( char const *bsp_unc_address )
+{
+}
+
+void CBugReporter::SetVMFName( char const *vmf_unc_address )
+{
+}
+
+void CBugReporter::AddIncludedFile( char const *filename )
+{
+}
+
+void CBugReporter::ResetIncludedFiles()
+{
+}
+
+void CBugReporter::SetExeName( char const *exename )
+{
+ Assert( m_pBug );
+ Q_strncpy( m_pBug->exename, exename, sizeof( m_pBug->exename ) );
+}
+
+void CBugReporter::SetGameDirectory( char const *pchGamedir )
+{
+ Assert( m_pBug );
+
+ Q_FileBase( pchGamedir, m_pBug->gamedir, sizeof( m_pBug->gamedir ) );
+}
+
+void CBugReporter::SetRAM( int ram )
+{
+ Assert( m_pBug );
+ m_pBug->ram = ram;
+}
+
+void CBugReporter::SetCPU( int cpu )
+{
+ Assert( m_pBug );
+ m_pBug->cpu = cpu;
+}
+
+void CBugReporter::SetProcessor( char const *processor )
+{
+ Assert( m_pBug );
+ Q_strncpy( m_pBug->processor, processor, sizeof( m_pBug->processor ) );
+}
+
+void CBugReporter::SetDXVersion( unsigned int high, unsigned int low, unsigned int vendor, unsigned int device )
+{
+ Assert( m_pBug );
+ m_pBug->dxversionhigh = high;
+ m_pBug->dxversionlow = low;
+ m_pBug->dxvendor = vendor;
+ m_pBug->dxdevice = device;
+}
+
+void CBugReporter::SetOSVersion( char const *osversion )
+{
+ Assert( m_pBug );
+ Q_strncpy( m_pBug->osversion, osversion, sizeof( m_pBug->osversion ) );
+}
+
+void CBugReporter::SetCSERAddress( const struct netadr_s& adr )
+{
+ m_cserIP = adr;
+}
+
+void CBugReporter::SetSteamUserID( void *steamid, int idsize )
+{
+ Assert( idsize == sizeof( uint64 ) );
+ m_SteamID.SetFromUint64( *((uint64*)steamid) );
+}
+
+EXPOSE_SINGLE_INTERFACE( CBugReporter, IBugReporter, INTERFACEVERSION_BUGREPORTER );
diff --git a/utils/bugreporter_public/bugreporter_public.vpc b/utils/bugreporter_public/bugreporter_public.vpc
new file mode 100644
index 0000000..2f540b2
--- /dev/null
+++ b/utils/bugreporter_public/bugreporter_public.vpc
@@ -0,0 +1,65 @@
+//-----------------------------------------------------------------------------
+// BUGREPORTER_PUBLIC.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin"
+
+$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE,..\common"
+ $PreprocessorDefinitions "$BASE;bugreporter_public_EXPORTS"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "$BASE Ws2_32.lib odbc32.lib odbccp32.lib" [$WIN32]
+ $SystemLibraries "iconv" [$OSXALL]
+ }
+}
+
+$Project "Bugreporter_public"
+{
+ $Folder "Source Files"
+ {
+ $File "$SRCDIR\public\blockingudpsocket.cpp"
+ $File "bugreporter_public.cpp"
+ $File "bugreporter_upload.cpp"
+ $File "$SRCDIR\public\mathlib\IceKey.H"
+ }
+
+ $Folder "Header Files"
+ {
+ $File "$SRCDIR\public\tier0\basetypes.h"
+ $File "$SRCDIR\public\blockingudpsocket.h"
+ $File "$SRCDIR\public\Color.h"
+ $File "$SRCDIR\public\tier0\commonmacros.h"
+ $File "$SRCDIR\public\tier0\dbg.h"
+ $File "$SRCDIR\public\tier0\fasttimer.h"
+ $File "$SRCDIR\public\filesystem.h"
+ $File "$SRCDIR\public\appframework\IAppSystem.h"
+ $File "$SRCDIR\public\vstdlib\IKeyValuesSystem.h"
+ $File "$SRCDIR\public\tier0\mem.h"
+ $File "$SRCDIR\public\tier0\memdbgoff.h"
+ $File "$SRCDIR\public\tier0\memdbgon.h"
+ $File "$SRCDIR\public\tier0\platform.h"
+ $File "$SRCDIR\public\tier0\protected_things.h"
+ $File "$SRCDIR\public\string_t.h"
+ $File "$SRCDIR\public\tier1\strtools.h"
+ $File "$SRCDIR\public\tier1\utlmemory.h"
+ $File "$SRCDIR\public\tier1\utlrbtree.h"
+ $File "$SRCDIR\public\vstdlib\vstdlib.h"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib mathlib
+ }
+
+}
diff --git a/utils/bugreporter_public/bugreporter_upload.cpp b/utils/bugreporter_public/bugreporter_upload.cpp
new file mode 100644
index 0000000..5c99eaf
--- /dev/null
+++ b/utils/bugreporter_public/bugreporter_upload.cpp
@@ -0,0 +1,969 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "basetypes.h"
+#ifdef WIN32
+#include <winsock.h>
+#elif defined(POSIX)
+#define INVALID_SOCKET -1
+#define SOCKET_ERROR -1
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#define closesocket close
+#else
+#error
+#endif
+#include "netadr.h"
+#include "tier1/strtools.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include "utlbuffer.h"
+#include "utlvector.h"
+#include "filesystem_tools.h"
+#include "cserserverprotocol_engine.h"
+#include "mathlib/IceKey.H"
+#include "bitbuf.h"
+#include "blockingudpsocket.h"
+#include "steamcommon.h"
+#include "steam/steamclientpublic.h"
+
+typedef unsigned int u32;
+typedef unsigned char u8;
+typedef unsigned short u16;
+
+namespace BugReportHarvester
+{
+
+ enum EFileType
+ {
+ eFileTypeBugReport,
+
+ eFILETYPECOUNT // Count number of legal values
+ };
+
+
+ enum ESendMethod
+ {
+ eSendMethodWholeRawFileNoBlocks,
+ eSendMethodCompressedBlocks, // TODO: Reenable compressed sending of minidumps
+
+ eSENDMETHODCOUNT // Count number of legal values
+ };
+
+}
+
+using namespace BugReportHarvester;
+
+// TODO: cut protocol version down to u8 if possible, to reduce bandwidth usage
+// for very frequent but tiny commands.
+typedef u32 ProtocolVersion_t;
+
+typedef u8 ProtocolAcceptanceFlag_t;
+typedef u8 ProtocolUnacceptableAck_t;
+
+typedef u32 MessageSequenceId_t;
+
+typedef u32 ServerSessionHandle_t;
+typedef u32 ClientSessionHandle_t;
+
+typedef u32 NetworkTransactionId_t;
+
+// Command codes are intentionally as small as possible to minimize bandwidth usage
+// for very frequent but tiny commands (e.g. GDS 'FindServer' commands).
+typedef u8 Command_t;
+
+// ... likewise response codes are as small as possible - we use this when we
+// ... can and revert to large types on a case by case basis.
+typedef u8 CommandResponse_t;
+
+
+// This define our standard type for length prefix for variable length messages
+// in wire protocols.
+// This is specifically used by CWSABUFWrapper::PrepareToReceiveLengthPrefixedMessage()
+// and its supporting functions.
+// It is defined here for generic (portable) network code to use when constructing
+// messages to be sent to peers that use the above function.
+// e.g. SteamValidateUserIDTickets.dll uses this for that purpose.
+
+// We support u16 or u32 (obviously switching between them breaks existing protocols
+// unless all components are switched simultaneously).
+typedef u32 NetworkMessageLengthPrefix_t;
+
+
+// Similarly, strings should be preceeded by their length.
+typedef u16 StringLengthPrefix_t;
+
+
+const ProtocolAcceptanceFlag_t cuProtocolIsNotAcceptable
+ = static_cast<ProtocolAcceptanceFlag_t>( 0 );
+
+const ProtocolAcceptanceFlag_t cuProtocolIsAcceptable
+ = static_cast<ProtocolAcceptanceFlag_t>( 1 );
+
+const Command_t cuMaxCommand
+ = static_cast<Command_t>(255);
+
+const CommandResponse_t cuMaxCommandResponse
+ = static_cast<CommandResponse_t>(255);
+
+// This is for mapping requests back to error ids for placing into the database appropriately.
+typedef u32 ContextID_t;
+
+// This is the version of the protocol used by latest-build clients.
+const ProtocolVersion_t cuCurrentProtocolVersion = 1;
+
+// This is the minimum protocol version number that the client must
+// be able to speak in order to communicate with the server.
+// The client sends its protocol version this before every command, and if we
+// don't support that version anymore then we tell it nicely. The client
+// should respond by doing an auto-update.
+const ProtocolVersion_t cuRequiredProtocolVersion = 1;
+
+
+namespace Commands
+{
+ const Command_t cuGracefulClose = 0;
+ const Command_t cuSendBugReport = 1;
+ const Command_t cuNumCommands = 2;
+ const Command_t cuNoCommandReceivedYet = cuMaxCommand;
+}
+
+
+namespace HarvestFileCommand
+{
+ typedef u32 SenderTypeId_t;
+ typedef u32 SenderTypeUniqueId_t;
+ typedef u32 SenderSourceCodeControlId_t;
+ typedef u32 FileSize_t;
+
+ // Legal values defined by EFileType
+ typedef u32 FileType_t;
+
+ // Legal values defined by ESendMethod
+ typedef u32 SendMethod_t;
+
+ const CommandResponse_t cuOkToSendFile = 0;
+ const CommandResponse_t cuFileTooBig = 1;
+ const CommandResponse_t cuInvalidSendMethod = 2;
+ const CommandResponse_t cuInvalidMaxCompressedChunkSize = 3;
+ const CommandResponse_t cuInvalidBugReportContext = 4;
+ const uint cuNumCommandResponses = 5;
+}
+
+//#############################################################################
+//
+// Class declaration: CWin32UploadBugReport
+//
+//#############################################################################
+//
+// Authors:
+//
+// Yahn Bernier
+//
+// Description and general notes:
+//
+// Handles uploading bug report data blobs to the CSERServer
+// (Client Stats & Error Reporting Server)
+
+typedef enum
+{
+ // General status
+ eBugReportUploadSucceeded = 0,
+ eBugReportUploadFailed,
+
+ // Specific status
+ eBugReportBadParameter,
+ eBugReportUnknownStatus,
+ eBugReportSendingBugReportHeaderSucceeded,
+ eBugReportSendingBugReportHeaderFailed,
+ eBugReportReceivingResponseSucceeded,
+ eBugReportReceivingResponseFailed,
+ eBugReportConnectToCSERServerSucceeded,
+ eBugReportConnectToCSERServerFailed,
+ eBugReportUploadingBugReportSucceeded,
+ eBugReportUploadingBugReportFailed
+} EBugReportUploadStatus;
+
+struct TBugReportProgress
+{
+ // A text string describing the current progress
+ char m_sStatus[ 512 ];
+};
+
+typedef void ( *BUGREPORTREPORTPROGRESSFUNC )( u32 uContext, const TBugReportProgress & rBugReportProgress );
+
+static void BugUploadProgress( u32 uContext, const TBugReportProgress & rBugReportProgress )
+{
+ // DevMsg( "%s\n", rBugReportProgress.m_sStatus );
+}
+
+struct TBugReportParameters
+{
+ // IP Address of the CSERServer to send the report to
+ netadr_t m_ipCSERServer;
+
+ TSteamGlobalUserID m_userid;
+
+ // Source Control Id (or build_number) of the product
+ u32 m_uEngineBuildNumber;
+ // Name of the .exe
+ char m_sExecutableName[ 64 ];
+ // Game directory
+ char m_sGameDirectory[ 64 ];
+ // Map name the server wants to upload statistics about
+ char m_sMapName[ 64 ];
+
+ u32 m_uRAM;
+ u32 m_uCPU;
+
+ char m_sProcessor[ 128 ];
+
+ u32 m_uDXVersionHigh;
+ u32 m_uDXVersionLow;
+ u32 m_uDXVendorId;
+ u32 m_uDXDeviceId;
+
+ char m_sOSVersion[ 64 ];
+
+ char m_sReportType[ 40 ];
+ char m_sEmail[ 80 ];
+ char m_sAccountName[ 64 ];
+
+ char m_sTitle[ 128 ];
+
+ char m_sBody[ 1024 ];
+
+ u32 m_uAttachmentFileSize;
+ char m_sAttachmentFile[ 128 ];
+
+ u32 m_uProgressContext;
+ BUGREPORTREPORTPROGRESSFUNC m_pOptionalProgressFunc;
+};
+
+// Note that this API is blocking, though the callback, if passed, can occur during execution.
+EBugReportUploadStatus Win32UploadBugReportBlocking
+(
+ const TBugReportParameters & rBugReportParameters // Input
+);
+
+ //-----------------------------------------------------------------------------
+// Purpose: encrypts an 8-byte sequence
+//-----------------------------------------------------------------------------
+inline void Encrypt8ByteSequence( IceKey& cipher, const unsigned char *plainText, unsigned char *cipherText)
+{
+ cipher.encrypt(plainText, cipherText);
+}
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void EncryptBuffer( IceKey& cipher, unsigned char *bufData, uint bufferSize)
+{
+ unsigned char *cipherText = bufData;
+ unsigned char *plainText = bufData;
+ uint bytesEncrypted = 0;
+
+ while (bytesEncrypted < bufferSize)
+ {
+ // encrypt 8 byte section
+ Encrypt8ByteSequence( cipher, plainText, cipherText);
+ bytesEncrypted += 8;
+ cipherText += 8;
+ plainText += 8;
+ }
+}
+
+bool UploadBugReport(
+ const netadr_t& cserIP,
+ const CSteamID &userid,
+ int build,
+ char const *title,
+ char const *body,
+ char const *exename,
+ char const *pchGamedir,
+ char const *mapname,
+ char const *reporttype,
+ char const *email,
+ char const *accountname,
+ int ram,
+ int cpu,
+ char const *processor,
+ unsigned int high,
+ unsigned int low,
+ unsigned int vendor,
+ unsigned int device,
+ char const *osversion,
+ char const *attachedfile,
+ unsigned int attachedfilesize
+)
+{
+ TBugReportParameters params;
+ Q_memset( &params, 0, sizeof( params ) );
+
+ params.m_ipCSERServer = cserIP;
+ params.m_userid.m_SteamLocalUserID.As64bits = userid.ConvertToUint64();
+
+ params.m_uEngineBuildNumber = build;
+ Q_strncpy( params.m_sExecutableName, exename, sizeof( params.m_sExecutableName ) );
+ Q_strncpy( params.m_sGameDirectory, pchGamedir, sizeof( params.m_sGameDirectory ) );
+ Q_strncpy( params.m_sMapName, mapname, sizeof( params.m_sMapName ) );
+
+ params.m_uRAM = ram;
+ params.m_uCPU = cpu;
+
+ Q_strncpy( params.m_sProcessor, processor, sizeof( params.m_sProcessor) );
+
+ params.m_uDXVersionHigh = high;
+ params.m_uDXVersionLow = low;
+ params.m_uDXVendorId = vendor;
+ params.m_uDXDeviceId = device;
+
+ Q_strncpy( params.m_sOSVersion, osversion, sizeof( params.m_sOSVersion ) );
+
+ Q_strncpy( params.m_sReportType, reporttype, sizeof( params.m_sReportType ) );
+ Q_strncpy( params.m_sEmail, email, sizeof( params.m_sEmail ) );
+ Q_strncpy( params.m_sAccountName, accountname, sizeof( params.m_sAccountName ) );
+
+ Q_strncpy( params.m_sTitle, title, sizeof( params.m_sTitle ) );
+ Q_strncpy( params.m_sBody, body, sizeof( params.m_sBody ) );
+
+ Q_strncpy( params.m_sAttachmentFile, attachedfile, sizeof( params.m_sAttachmentFile ) );
+ params.m_uAttachmentFileSize = attachedfilesize;
+
+ params.m_uProgressContext = 1u;
+ params.m_pOptionalProgressFunc = BugUploadProgress;
+
+ EBugReportUploadStatus result = Win32UploadBugReportBlocking( params );
+ return ( result == eBugReportUploadSucceeded ) ? true : false;
+
+}
+
+void UpdateProgress( const TBugReportParameters & params, char const *fmt, ... )
+{
+ if ( !params.m_pOptionalProgressFunc )
+ {
+ return;
+ }
+
+ char str[ 2048 ];
+ va_list argptr;
+ va_start( argptr, fmt );
+ _vsnprintf( str, sizeof( str ) - 1, fmt, argptr );
+ va_end( argptr );
+
+ char outstr[ 2060 ];
+ Q_snprintf( outstr, sizeof( outstr ), "(%u): %s", params.m_uProgressContext, str );
+
+ TBugReportProgress progress;
+ Q_strncpy( progress.m_sStatus, outstr, sizeof( progress.m_sStatus ) );
+
+ // Invoke the callback
+ ( *params.m_pOptionalProgressFunc )( params.m_uProgressContext, progress );
+}
+
+class CWin32UploadBugReport
+{
+public:
+ explicit CWin32UploadBugReport(
+ const netadr_t & harvester,
+ const TBugReportParameters & rBugReportParameters,
+ u32 contextid );
+ ~CWin32UploadBugReport();
+
+ EBugReportUploadStatus Upload( CUtlBuffer& buf );
+
+private:
+
+ enum States
+ {
+ eCreateTCPSocket = 0,
+ eConnectToHarvesterServer,
+ eSendProtocolVersion,
+ eReceiveProtocolOkay,
+ eSendUploadCommand,
+ eReceiveOKToSendFile,
+ eSendWholeFile, // This could push chunks onto the wire, but we'll just use a whole buffer for now.
+ eReceiveFileUploadSuccess,
+ eSendGracefulClose,
+ eCloseTCPSocket
+ };
+
+ bool CreateTCPSocket( EBugReportUploadStatus& status, CUtlBuffer& buf );
+ bool ConnectToHarvesterServer( EBugReportUploadStatus& status, CUtlBuffer& buf );
+ bool SendProtocolVersion( EBugReportUploadStatus& status, CUtlBuffer& buf );
+ bool ReceiveProtocolOkay( EBugReportUploadStatus& status, CUtlBuffer& buf );
+ bool SendUploadCommand( EBugReportUploadStatus& status, CUtlBuffer& buf );
+ bool ReceiveOKToSendFile( EBugReportUploadStatus& status, CUtlBuffer& buf );
+ bool SendWholeFile( EBugReportUploadStatus& status, CUtlBuffer& buf );
+ bool ReceiveFileUploadSuccess( EBugReportUploadStatus& status, CUtlBuffer& buf );
+ bool SendGracefulClose( EBugReportUploadStatus& status, CUtlBuffer& buf );
+ bool CloseTCPSocket( EBugReportUploadStatus& status, CUtlBuffer& buf );
+
+ typedef bool ( CWin32UploadBugReport::*pfnProtocolStateHandler )( EBugReportUploadStatus& status, CUtlBuffer& buf );
+ struct FSMState_t
+ {
+ FSMState_t( uint f, pfnProtocolStateHandler s ) :
+ first( f ),
+ second( s )
+ {
+ }
+
+ uint first;
+ pfnProtocolStateHandler second;
+ };
+
+ void AddState( uint StateIndex, pfnProtocolStateHandler handler );
+ void SetNextState( uint StateIndex );
+ bool DoBlockingReceive( uint bytesExpected, CUtlBuffer& buf );
+
+ CUtlVector< FSMState_t > m_States;
+ uint m_uCurrentState;
+ struct sockaddr_in m_HarvesterSockAddr;
+ uint m_SocketTCP;
+ const TBugReportParameters &m_rBugReportParameters; //lint !e1725
+ u32 m_ContextID;
+};
+
+CWin32UploadBugReport::CWin32UploadBugReport(
+ const netadr_t & harvester,
+ const TBugReportParameters & rBugReportParameters,
+ u32 contextid ) :
+ m_States(),
+ m_uCurrentState( eCreateTCPSocket ),
+ m_HarvesterSockAddr(),
+ m_SocketTCP( 0 ),
+ m_rBugReportParameters( rBugReportParameters ),
+ m_ContextID( contextid )
+{
+ harvester.ToSockadr( (struct sockaddr *)&m_HarvesterSockAddr );
+
+ AddState( eCreateTCPSocket, &CWin32UploadBugReport::CreateTCPSocket );
+ AddState( eConnectToHarvesterServer, &CWin32UploadBugReport::ConnectToHarvesterServer );
+ AddState( eSendProtocolVersion, &CWin32UploadBugReport::SendProtocolVersion );
+ AddState( eReceiveProtocolOkay, &CWin32UploadBugReport::ReceiveProtocolOkay );
+ AddState( eSendUploadCommand, &CWin32UploadBugReport::SendUploadCommand );
+ AddState( eReceiveOKToSendFile, &CWin32UploadBugReport::ReceiveOKToSendFile );
+ AddState( eSendWholeFile, &CWin32UploadBugReport::SendWholeFile );
+ AddState( eReceiveFileUploadSuccess, &CWin32UploadBugReport::ReceiveFileUploadSuccess );
+ AddState( eSendGracefulClose, &CWin32UploadBugReport::SendGracefulClose );
+ AddState( eCloseTCPSocket, &CWin32UploadBugReport::CloseTCPSocket );
+}
+
+CWin32UploadBugReport::~CWin32UploadBugReport()
+{
+ if ( m_SocketTCP != 0 )
+ {
+ closesocket( m_SocketTCP ); //lint !e534
+ m_SocketTCP = 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+//
+// Function: DoBlockingReceive()
+//
+//-----------------------------------------------------------------------------
+bool CWin32UploadBugReport::DoBlockingReceive( uint bytesExpected, CUtlBuffer& buf )
+{
+ uint totalReceived = 0;
+
+ buf.Purge();
+ for ( ;; )
+ {
+ char temp[ 8192 ];
+
+ int bytesReceived = recv( m_SocketTCP, temp, sizeof( temp ), 0 );
+ if ( bytesReceived <= 0 )
+ return false;
+
+ buf.Put( ( const void * )temp, (u32)bytesReceived );
+ totalReceived = buf.TellPut();
+ if ( totalReceived >= bytesExpected )
+ break;
+
+ }
+ return true;
+}
+
+void CWin32UploadBugReport::AddState( uint StateIndex, pfnProtocolStateHandler handler )
+{
+ FSMState_t newState( StateIndex, handler );
+ m_States.AddToTail( newState );
+}
+
+EBugReportUploadStatus CWin32UploadBugReport::Upload( CUtlBuffer& buf )
+{
+ UpdateProgress( m_rBugReportParameters, "Commencing bug report upload connection." );
+
+ EBugReportUploadStatus result = eBugReportUploadSucceeded;
+ // Run the state machine
+ while ( 1 )
+ {
+ Assert( m_States[ m_uCurrentState ].first == m_uCurrentState );
+ pfnProtocolStateHandler handler = m_States[ m_uCurrentState ].second;
+
+ if ( !(this->*handler)( result, buf ) )
+ {
+ return result;
+ }
+ }
+}
+
+void CWin32UploadBugReport::SetNextState( uint StateIndex )
+{
+ Assert( StateIndex > m_uCurrentState );
+ m_uCurrentState = StateIndex;
+}
+
+bool CWin32UploadBugReport::CreateTCPSocket( EBugReportUploadStatus& status, CUtlBuffer& /*buf*/ )
+{
+ UpdateProgress( m_rBugReportParameters, "Creating bug report upload socket." );
+
+ m_SocketTCP = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
+ if ( m_SocketTCP == (uint)SOCKET_ERROR )
+ {
+ UpdateProgress( m_rBugReportParameters, "Socket creation failed." );
+
+ status = eBugReportUploadFailed;
+ return false;
+ }
+
+ SetNextState( eConnectToHarvesterServer );
+ return true;
+}
+
+bool CWin32UploadBugReport::ConnectToHarvesterServer( EBugReportUploadStatus& status, CUtlBuffer& /*buf*/ )
+{
+ UpdateProgress( m_rBugReportParameters, "Connecting to bug report harvesting server." );
+
+ if ( connect( m_SocketTCP, (const sockaddr *)&m_HarvesterSockAddr, sizeof( m_HarvesterSockAddr ) ) == SOCKET_ERROR )
+ {
+ UpdateProgress( m_rBugReportParameters, "Connection failed." );
+
+ status = eBugReportConnectToCSERServerFailed;
+ return false;
+ }
+
+ SetNextState( eSendProtocolVersion );
+ return true;
+}
+
+bool CWin32UploadBugReport::SendProtocolVersion( EBugReportUploadStatus& status, CUtlBuffer& buf )
+{
+ UpdateProgress( m_rBugReportParameters, "Sending bug report harvester protocol info." );
+ buf.SetBigEndian( true );
+ // Send protocol version
+ buf.Purge();
+ buf.PutInt( cuCurrentProtocolVersion );
+
+ if ( send( m_SocketTCP, (const char *)buf.Base(), (int)buf.TellPut(), 0 ) == SOCKET_ERROR )
+ {
+ UpdateProgress( m_rBugReportParameters, "Send failed." );
+
+ status = eBugReportUploadFailed;
+ return false;
+ }
+
+ SetNextState( eReceiveProtocolOkay );
+ return true;
+}
+
+bool CWin32UploadBugReport::ReceiveProtocolOkay( EBugReportUploadStatus& status, CUtlBuffer& buf )
+{
+ UpdateProgress( m_rBugReportParameters, "Receiving harvesting protocol acknowledgement." );
+ buf.Purge();
+
+ // Now receive the protocol is acceptable token from the server
+ if ( !DoBlockingReceive( 1, buf ) )
+ {
+ UpdateProgress( m_rBugReportParameters, "Didn't receive protocol failure data." );
+
+ status = eBugReportUploadFailed;
+ return false;
+ }
+
+ bool protocolokay = buf.GetChar() ? true : false;
+ if ( !protocolokay )
+ {
+ UpdateProgress( m_rBugReportParameters, "Server rejected protocol." );
+
+ status = eBugReportUploadFailed;
+ return false;
+ }
+
+ UpdateProgress( m_rBugReportParameters, "Protocol OK." );
+
+ SetNextState( eSendUploadCommand );
+ return true;
+}
+
+bool CWin32UploadBugReport::SendUploadCommand( EBugReportUploadStatus& status, CUtlBuffer& buf )
+{
+ UpdateProgress( m_rBugReportParameters, "Sending harvesting protocol upload request." );
+// Send upload command
+ buf.Purge();
+
+ NetworkMessageLengthPrefix_t messageSize
+ (
+ sizeof( Command_t )
+ + sizeof( ContextID_t )
+ + sizeof( HarvestFileCommand::FileSize_t )
+ + sizeof( HarvestFileCommand::SendMethod_t )
+ + sizeof( HarvestFileCommand::FileSize_t )
+ );
+
+ // Prefix the length to the command
+ buf.PutInt( (int)messageSize );
+ buf.PutChar( Commands::cuSendBugReport );
+ buf.PutInt( (int)m_ContextID );
+
+ buf.PutInt( (int)m_rBugReportParameters.m_uAttachmentFileSize );
+ buf.PutInt( static_cast<HarvestFileCommand::SendMethod_t>( eSendMethodWholeRawFileNoBlocks ) );
+ buf.PutInt( static_cast<HarvestFileCommand::FileSize_t>( 0 ) );
+
+ // Send command to server
+ if ( send( m_SocketTCP, (const char *)buf.Base(), (int)buf.TellPut(), 0 ) == SOCKET_ERROR )
+ {
+ UpdateProgress( m_rBugReportParameters, "Send failed." );
+
+ status = eBugReportUploadFailed;
+ return false;
+ }
+
+ SetNextState( eReceiveOKToSendFile );
+ return true;
+}
+
+bool CWin32UploadBugReport::ReceiveOKToSendFile( EBugReportUploadStatus& status, CUtlBuffer& buf )
+{
+ UpdateProgress( m_rBugReportParameters, "Receive bug report harvesting protocol upload permissible." );
+
+ // Now receive the protocol is acceptable token from the server
+ if ( !DoBlockingReceive( 1, buf ) )
+ {
+ UpdateProgress( m_rBugReportParameters, "Receive failed." );
+ status = eBugReportUploadFailed;
+ return false;
+ }
+
+ bool dosend = false;
+ CommandResponse_t cmd = (CommandResponse_t)buf.GetChar();
+ switch ( cmd )
+ {
+ case HarvestFileCommand::cuOkToSendFile:
+ {
+ dosend = true;
+ }
+ break;
+ case HarvestFileCommand::cuFileTooBig:
+ case HarvestFileCommand::cuInvalidSendMethod:
+ case HarvestFileCommand::cuInvalidMaxCompressedChunkSize:
+ case HarvestFileCommand::cuInvalidBugReportContext:
+ default:
+ break;
+ }
+
+ if ( !dosend )
+ {
+ UpdateProgress( m_rBugReportParameters, "Server rejected upload command." );
+
+ status = eBugReportUploadFailed;
+ return false;
+ }
+
+ SetNextState( eSendWholeFile );
+ return true;
+}
+
+bool CWin32UploadBugReport::SendWholeFile( EBugReportUploadStatus& status, CUtlBuffer& /*buf*/ )
+{
+ UpdateProgress( m_rBugReportParameters, "Uploading bug report data." );
+ // Send to server
+ char *filebuf = NULL;
+ size_t sizeactual = g_pFileSystem->Size( m_rBugReportParameters.m_sAttachmentFile );
+ if ( sizeactual > 0 )
+ {
+ filebuf = new char[ sizeactual + 1 ];
+ if ( filebuf )
+ {
+ FileHandle_t fh;
+ fh = g_pFileSystem->Open( m_rBugReportParameters.m_sAttachmentFile, "rb" );
+ if ( FILESYSTEM_INVALID_HANDLE != fh )
+ {
+ g_pFileSystem->Read( (void *)filebuf, sizeactual, fh );
+
+ g_pFileSystem->Close( fh );
+ }
+ filebuf[ sizeactual ] = 0;
+ }
+ }
+ if ( !sizeactual || !filebuf )
+ {
+ UpdateProgress( m_rBugReportParameters, "bug .zip file size zero or unable to allocate memory for file." );
+
+ status = eBugReportUploadFailed;
+ if ( filebuf )
+ {
+ delete[] filebuf;
+ }
+ return false;
+ }
+
+ // Send to server
+ bool bret = true;
+ if ( send( m_SocketTCP, filebuf, (int)sizeactual, 0 ) == SOCKET_ERROR )
+ {
+ bret = false;
+ UpdateProgress( m_rBugReportParameters, "Send failed." );
+
+ status = eBugReportUploadFailed;
+ }
+ else
+ {
+ SetNextState( eReceiveFileUploadSuccess );
+ }
+
+ delete[] filebuf;
+
+ return bret;
+}
+
+bool CWin32UploadBugReport::ReceiveFileUploadSuccess( EBugReportUploadStatus& status, CUtlBuffer& buf )
+{
+ UpdateProgress( m_rBugReportParameters, "Receiving bug report upload success/fail message." );
+
+ // Now receive the protocol is acceptable token from the server
+ if ( !DoBlockingReceive( 1, buf ) )
+ {
+ UpdateProgress( m_rBugReportParameters, "Receive failed." );
+
+ status = eBugReportUploadFailed;
+ return false;
+ }
+
+ bool success = buf.GetChar() == 1 ? true : false;
+ if ( !success )
+ {
+ UpdateProgress( m_rBugReportParameters, "Upload failed." );
+
+ status = eBugReportUploadFailed;
+ return false;
+ }
+
+ UpdateProgress( m_rBugReportParameters, "Upload OK." );
+
+ SetNextState( eSendGracefulClose );
+ return true;
+}
+
+bool CWin32UploadBugReport::SendGracefulClose( EBugReportUploadStatus& status, CUtlBuffer& buf )
+{
+ UpdateProgress( m_rBugReportParameters, "Closing connection to server." );
+
+ // Now send disconnect command
+ buf.Purge();
+
+ size_t messageSize = sizeof( Command_t );
+
+ buf.PutInt( (int)messageSize );
+ buf.PutChar( Commands::cuGracefulClose );
+
+ if ( send( m_SocketTCP, (const char *)buf.Base(), (int)buf.TellPut(), 0 ) == SOCKET_ERROR )
+ {
+ UpdateProgress( m_rBugReportParameters, "Send failed." );
+
+ status = eBugReportUploadFailed;
+ return false;
+ }
+
+ SetNextState( eCloseTCPSocket );
+ return true;
+}
+
+bool CWin32UploadBugReport::CloseTCPSocket( EBugReportUploadStatus& status, CUtlBuffer& /*buf*/ )
+{
+ UpdateProgress( m_rBugReportParameters, "Closing socket, upload succeeded." );
+
+ closesocket( m_SocketTCP );//lint !e534
+ m_SocketTCP = 0;
+
+ status = eBugReportUploadSucceeded;
+ // NOTE: Returning false here ends the state machine!!!
+ return false;
+}
+
+EBugReportUploadStatus Win32UploadBugReportBlocking
+(
+ const TBugReportParameters & rBugReportParameters
+)
+{
+ EBugReportUploadStatus status = eBugReportUploadFailed;
+
+ CUtlBuffer buf( 2048 );
+
+ UpdateProgress( rBugReportParameters, "Creating initial report." );
+
+ buf.SetBigEndian( false );
+
+ buf.Purge();
+ buf.PutChar( C2M_BUGREPORT );
+ buf.PutChar( '\n' );
+ buf.PutChar( C2M_BUGREPORT_PROTOCOL_VERSION );
+
+ // See CSERServerProtocol.h for format
+
+ // encryption object
+ IceKey cipher(1); /* medium encryption level */
+ unsigned char ucEncryptionKey[8] = { 200,145,10,149,195,190,108,243 };
+
+ cipher.set( ucEncryptionKey );
+
+ CUtlBuffer encrypted( 2000 );
+
+ u8 corruption_identifier = 0x01;
+
+ encrypted.PutChar( corruption_identifier );
+
+ encrypted.PutInt( rBugReportParameters.m_uEngineBuildNumber ); // build_identifier
+
+ encrypted.PutString( rBugReportParameters.m_sExecutableName );
+ encrypted.PutString( rBugReportParameters.m_sGameDirectory );
+ encrypted.PutString( rBugReportParameters.m_sMapName );
+
+ encrypted.PutInt( rBugReportParameters.m_uRAM ); // ram mb
+ encrypted.PutInt( rBugReportParameters.m_uCPU ); // cpu mhz
+
+ encrypted.PutString( rBugReportParameters.m_sProcessor );
+
+ encrypted.PutInt( rBugReportParameters.m_uDXVersionHigh ); // driver version high part
+ encrypted.PutInt( rBugReportParameters.m_uDXVersionLow ); // driver version low part
+ encrypted.PutInt( rBugReportParameters.m_uDXVendorId ); // dxvendor id
+ encrypted.PutInt( rBugReportParameters.m_uDXDeviceId ); // dxdevice id
+
+ encrypted.PutString( rBugReportParameters.m_sOSVersion );
+
+ encrypted.PutInt( rBugReportParameters.m_uAttachmentFileSize );
+
+ // protocol version 2 stuff
+ {
+ encrypted.PutString( rBugReportParameters.m_sReportType );
+ encrypted.PutString( rBugReportParameters.m_sEmail );
+ encrypted.PutString( rBugReportParameters.m_sAccountName );
+ }
+
+ // protocol version 3 stuff
+ {
+ encrypted.Put( &rBugReportParameters.m_userid, sizeof( rBugReportParameters.m_userid ) );
+ }
+
+ encrypted.PutString( rBugReportParameters.m_sTitle );
+
+ int bodylen = Q_strlen( rBugReportParameters.m_sBody ) + 1;
+
+ encrypted.PutInt( bodylen );
+ encrypted.Put( rBugReportParameters.m_sBody, bodylen );
+
+ while ( encrypted.TellPut() % 8 )
+ {
+ encrypted.PutChar( 0 );
+ }
+
+ EncryptBuffer( cipher, (unsigned char *)encrypted.Base(), encrypted.TellPut() );
+
+ buf.PutShort( (int)encrypted.TellPut() );
+ buf.Put( (unsigned char *)encrypted.Base(), encrypted.TellPut() );
+
+ CBlockingUDPSocket bcs;
+ if ( !bcs.IsValid() )
+ {
+ return eBugReportUploadFailed;
+ }
+
+ struct sockaddr_in sa;
+ rBugReportParameters.m_ipCSERServer.ToSockadr( (struct sockaddr *)&sa );
+
+ UpdateProgress( rBugReportParameters, "Sending bug report to server." );
+
+ bcs.SendSocketMessage( sa, (const u8 *)buf.Base(), buf.TellPut() ); //lint !e534
+
+ UpdateProgress( rBugReportParameters, "Waiting for response." );
+
+ if ( bcs.WaitForMessage( 2.0f ) )
+ {
+ UpdateProgress( rBugReportParameters, "Received response." );
+
+ struct sockaddr_in replyaddress;
+ buf.EnsureCapacity( 2048 );
+
+ uint bytesReceived = bcs.ReceiveSocketMessage( &replyaddress, (u8 *)buf.Base(), 2048 );
+ if ( bytesReceived > 0 )
+ {
+ // Fixup actual size
+ buf.SeekPut( CUtlBuffer::SEEK_HEAD, bytesReceived );
+
+ UpdateProgress( rBugReportParameters, "Checking response." );
+
+ // Parse out data
+ u8 msgtype = (u8)buf.GetChar();
+ if ( M2C_ACKBUGREPORT != msgtype )
+ {
+ UpdateProgress( rBugReportParameters, "Request denied, invalid message type." );
+ return eBugReportSendingBugReportHeaderFailed;
+ }
+ bool validProtocol = (u8)buf.GetChar() == 1 ? true : false;
+ if ( !validProtocol )
+ {
+ UpdateProgress( rBugReportParameters, "Request denied, invalid message protocol." );
+ return eBugReportSendingBugReportHeaderFailed;
+ }
+
+ u8 disposition = (u8)buf.GetChar();
+ if ( BR_REQEST_FILES != disposition )
+ {
+ // Server doesn't want a bug report, oh well
+ if ( rBugReportParameters.m_uAttachmentFileSize > 0 )
+ {
+ UpdateProgress( rBugReportParameters, "Bug report accepted, attachment rejected (server too busy)" );
+ }
+ else
+ {
+ UpdateProgress( rBugReportParameters, "Bug report accepted." );
+ }
+
+ return eBugReportUploadSucceeded;
+ }
+
+ // Read in the bug report info parameters
+ u32 harvester_ip = (u32)buf.GetInt();
+ u16 harvester_port = (u16)buf.GetShort();
+ u32 dumpcontext = (u32)buf.GetInt();
+
+ sockaddr_in adr;
+ adr.sin_family = AF_INET;
+ adr.sin_port = htons( harvester_port );
+#ifdef WIN32
+ adr.sin_addr.S_un.S_addr = harvester_ip;
+#else
+ adr.sin_addr.s_addr = harvester_ip;
+#endif
+ netadr_t BugReportHarvesterFSMIPAddress;
+ BugReportHarvesterFSMIPAddress.SetFromSockadr( (struct sockaddr *)&adr );
+
+ UpdateProgress( rBugReportParameters, "Server requested bug report upload." );
+
+ // Keep using the same scratch buffer for messaging
+ CWin32UploadBugReport uploader( BugReportHarvesterFSMIPAddress, rBugReportParameters, dumpcontext );
+ status = uploader.Upload( buf );
+ }
+ }
+ else
+ {
+ UpdateProgress( rBugReportParameters, "No response from server." );
+ }
+
+ return status;
+}