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.

172 lines
5.0 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include <windows.h>
  7. #include "vmpi.h"
  8. #include "vmpi_transfer.h"
  9. #include "cmdlib.h"
  10. #include "tier0/icommandline.h"
  11. #include "vmpi_tools_shared.h"
  12. #include "tools_minidump.h"
  13. #include <conio.h>
  14. void MyDisconnectHandler( int procID, const char *pReason )
  15. {
  16. Error( "Premature disconnect.\n" );
  17. }
  18. void DownloadFile( const char *pCachePath, const char *pRemoteFileBase, const char *pFilename )
  19. {
  20. // Setup local and remote filenames.
  21. char remoteFilename[MAX_PATH];
  22. char localFilename[MAX_PATH];
  23. V_ComposeFileName( pRemoteFileBase, pFilename, remoteFilename, sizeof( remoteFilename ) );
  24. V_ComposeFileName( pCachePath, pFilename, localFilename, sizeof( localFilename ) );
  25. // Read the file in.
  26. FileHandle_t fpSrc = g_pFileSystem->Open( remoteFilename, "rb" );
  27. if ( fpSrc == FILESYSTEM_INVALID_HANDLE )
  28. {
  29. Error( "Unable to open %s on master.\n", remoteFilename );
  30. }
  31. unsigned int fileSize = g_pFileSystem->Size( fpSrc );
  32. CUtlVector<char> data;
  33. data.SetSize( fileSize );
  34. g_pFileSystem->Read( data.Base(), fileSize, fpSrc );
  35. g_pFileSystem->Close( fpSrc );
  36. // Now write the file to disk.
  37. FILE *fpDest = fopen( localFilename, "wb" );
  38. if ( !fpDest )
  39. {
  40. Error( "Can't open %s for writing.\n", localFilename );
  41. }
  42. fwrite( data.Base(), 1, data.Count(), fpDest );
  43. fclose( fpDest );
  44. Warning( "Got file: %s\n", pFilename );
  45. }
  46. #if 0
  47. SpewRetval_t MySpewFunc( SpewType_t spewType, const tchar *pMsg )
  48. {
  49. printf( "%s", pMsg );
  50. if ( spewType == SPEW_ERROR )
  51. {
  52. printf( "\nWaiting for keypress to quit...\n" );
  53. getch();
  54. TerminateProcess( GetCurrentProcess(), 1 );
  55. }
  56. return SPEW_CONTINUE;
  57. }
  58. #endif
  59. int RunVMPITransferWorker( int argc, char **argv )
  60. {
  61. if ( !VMPI_Init( argc, argv, NULL, MyDisconnectHandler, VMPI_RUN_NETWORKED, true ) )
  62. {
  63. return 1;
  64. }
  65. SetupToolsMinidumpHandler( VMPI_ExceptionFilter );
  66. if ( !FileSystem_Init( ".", 0, FS_INIT_COMPATIBILITY_MODE ) )
  67. return 1;
  68. ICommandLine *pCommandLine = CommandLine();
  69. // Look for the cache path and file base args.
  70. const char *pCachePath = pCommandLine->ParmValue( "-CachePath", (char*)NULL );
  71. if ( !pCachePath )
  72. Error( "No -CachePath specified." );
  73. const char *pRemoteFileBase = pCommandLine->ParmValue( "-mpi_filebase", (char*)NULL );
  74. if ( !pRemoteFileBase )
  75. Error( "No -mpi_filebase specified." );
  76. // Now just ask the master for each file.
  77. for ( int i=1; i < pCommandLine->ParmCount()-1; i++ )
  78. {
  79. const char *pParm = pCommandLine->GetParm( i );
  80. if ( V_stricmp( pParm, "-mpi_file" ) == 0 )
  81. {
  82. const char *pNextParm = pCommandLine->GetParm( i+1 );
  83. DownloadFile( pCachePath, pRemoteFileBase, pNextParm );
  84. ++i;
  85. }
  86. }
  87. // Ok, we're done. Write the status file so the service knows all the files are ready to go.
  88. char statusFilename[MAX_PATH];
  89. V_ComposeFileName( pCachePath, "ReadyToGo.txt", statusFilename, sizeof( statusFilename ) );
  90. FILE *fp = fopen( statusFilename, "wb" );
  91. fclose( fp );
  92. return 0;
  93. }
  94. // In this mode, we just initialize VMPI appropriately, and it'll host out the specified files.
  95. // The command line to vmpi_transfer is -PatchHost -PatchDirectory <directory>
  96. // Sample: vmpi_transfer -PatchHost -mpi_PatchDirectory \\fileserver\vmpi\patch1 -mpi_PatchWorkers <count> <ip1> <ip2>...
  97. // Then it'll tell those workers to connect and it'll send them the files in the specified directory.
  98. int RunVMPITransferMaster( int argc, char **argv )
  99. {
  100. // Since we didn't use -mpi_worker on the command line, VMPI will init as the master.
  101. // We put a special character in front of the dependency filename, which tells it the dependencies
  102. // consist of every file in the specified directory.
  103. VMPI_Init_PatchMaster( argc, argv );
  104. if ( !FileSystem_Init( ".", 0, FS_INIT_COMPATIBILITY_MODE ) )
  105. return 1;
  106. Msg( "Hosting patch files. Press ESC to exit. " );
  107. while ( 1 )
  108. {
  109. VMPI_DispatchNextMessage( 100 );
  110. if ( kbhit() )
  111. {
  112. if ( getch() == 27 )
  113. break;
  114. }
  115. }
  116. return 0;
  117. }
  118. // --------------------------------------------------------------------------------- //
  119. // Purpose: This app is used by vmpi_service to acquire the executables for
  120. // a VMPI job. When the service is asked to join a job, it runs this program
  121. // to connect to the VMPI master and download all the exes for the job.
  122. //
  123. // This app is ALSO used to do patches. vmpi_browser_services runs it with a list
  124. // of machines it wants to patch. Then it runs as the VMPI master and instead of
  125. // broadcasting its presence, it sends messages to the specific list of machines.
  126. // --------------------------------------------------------------------------------- //
  127. int main( int argc, char **argv )
  128. {
  129. InstallSpewFunction();
  130. CommandLine()->CreateCmdLine( argc, argv );
  131. int ret;
  132. if ( CommandLine()->FindParm( "-PatchHost" ) == 0 )
  133. {
  134. ret = RunVMPITransferWorker( argc, argv );
  135. }
  136. else
  137. {
  138. ret = RunVMPITransferMaster( argc, argv );
  139. }
  140. CmdLib_Cleanup();
  141. return ret;
  142. }