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