void AdjustSuperDebugArgs( CUtlVector<char*> &args ) { // Get the directory this exe was run out of. char filename[512]; if ( GetModuleFileName( GetModuleHandle( NULL ), filename, sizeof( filename ) ) == 0 ) return; char *pLastSlash = filename; char *pCurPos = filename; while ( *pCurPos ) { if ( *pCurPos == '/' || *pCurPos == '\\' ) pLastSlash = pCurPos; ++pCurPos; } *pLastSlash = 0; // In superdebug mode, run it out of c:/hl2/bin. const char *pBase = args[0]; const char *pBaseCur = pBase; while ( *pBaseCur ) { if ( *pBaseCur == '/' || *pBaseCur == '\\' || *pBaseCur == ':' ) { pBase = pBaseCur+1; pBaseCur = pBase; } ++pBaseCur; } int maxLen = 64 + strlen( pBase ) + 1; char *pNewFilename = new char[maxLen]; _snprintf( pNewFilename, maxLen, "%s\\%s", filename, pBase ); delete args[0]; args[0] = pNewFilename; // Now insert -allowdebug. const char *pAllowDebug = "-allowdebug"; char *pToInsert = new char[ strlen( pAllowDebug ) + 1 ]; strcpy( pToInsert, pAllowDebug ); args.InsertAfter( 0, pToInsert ); }
void HandlePacket_LOOKING_FOR_WORKERS( bf_read &buf, const CIPAddr &ipFrom ) { // If we're downloading files for a job request, don't process any more "looking for workers" packets. if ( g_Waiting_hProcess ) return; // This will be a nonzero-length string if patching. char versionString[512]; buf.ReadString( versionString, sizeof( versionString ) ); int iPort = buf.ReadShort(); int iPriority = buf.ReadShort(); // Make sure we don't run the same job more than once. if ( !CheckJobID( buf, g_CurJobID ) ) return; CUtlVector<char*> newArgv; GetArgsFromBuffer( buf, newArgv, &g_Waiting_bShowAppWindow ); bool bForcePatch = false; if ( buf.GetNumBytesLeft() >= 1 ) bForcePatch = (buf.ReadByte() != 0); int iDownloaderPort = iPort; if ( buf.GetNumBytesLeft() >= 2 ) iDownloaderPort = buf.ReadShort(); // Add these arguments after the executable filename to tell the program // that it's an MPI worker and who to connect to. char strDownloaderIP[128], strMainIP[128]; V_snprintf( strDownloaderIP, sizeof( strDownloaderIP ), "%d.%d.%d.%d:%d", ipFrom.ip[0], ipFrom.ip[1], ipFrom.ip[2], ipFrom.ip[3], iDownloaderPort ); V_snprintf( strMainIP, sizeof( strMainIP ), "%d.%d.%d.%d:%d", ipFrom.ip[0], ipFrom.ip[1], ipFrom.ip[2], ipFrom.ip[3], iPort ); // (-mpi is already on the command line of whoever ran the app). // AppendArg( commandLine, sizeof( commandLine ), "-mpi" ); newArgv.InsertAfter( 0, CopyString( "-mpi_worker" ) ); newArgv.InsertAfter( 1, CopyString( strDownloaderIP ) ); // If the version string is set, then this is a patch. bool bPatching = false; if ( versionString[0] != 0 ) { bPatching = true; // Check that we haven't applied this patch version yet. This case usually happens right after we've applied a patch // and we're restarting. The vmpi_transfer master is still pinging us telling us to patch, but we don't want to // reapply this patch. if ( atof( versionString ) <= atof( g_VersionString ) && !bForcePatch ) { newArgv.PurgeAndDeleteElements(); return; } // Ok, it's a new version. Get rid of whatever was running before. KillRunningProcess( "Starting a patch..", true ); } // If there's already a job running, only interrupt it if this new one has a higher priority. if ( WaitForProcessToExit() ) { if ( iPriority > g_CurJobPriority ) { KillRunningProcess( "Interrupted by a higher priority process", true ); } else { // This means we're already running a job with equal to or greater priority than // the one that has been requested. We're going to ignore this request. newArgv.PurgeAndDeleteElements(); return; } } // Responses go here. g_CurRespondAddr = ipFrom; // Also look for -mpi_ShowAppWindow in the args to the service. if ( !g_Waiting_bShowAppWindow && FindArg( __argc, __argv, "-mpi_ShowAppWindow" ) ) g_Waiting_bShowAppWindow = true; // Copy all the files from the master and put them in our cache dir to run with. char cacheDir[MAX_PATH]; if ( StartDownloadingAppFiles( newArgv, cacheDir, sizeof( cacheDir ), g_Waiting_bShowAppWindow, &g_Waiting_hProcess, bPatching ) ) { // After it's downloaded, we want it to switch to the main connection port. if ( newArgv.Count() >= 3 && V_stricmp( newArgv[2], strDownloaderIP ) == 0 ) { delete newArgv[2]; newArgv[2] = CopyString( strMainIP ); } g_Waiting_StartTime = Plat_FloatTime(); g_Waiting_Argv.PurgeAndDeleteElements(); g_Waiting_Argv = newArgv; g_Waiting_Priority = iPriority; g_Waiting_bPatching = bPatching; newArgv.Purge(); } else { newArgv.PurgeAndDeleteElements(); } // Remember that we tried to run this job so we don't try to run it again. AddJobMemory( g_CurJobID ); SendStateToServicesBrowsers(); }
// -------------------------------------------------------------------------------- // // Purpose: Launches vmpi_transfer.exe to download the required // files from the master so we can launch. // // If successful, it sets hProcess to the process handle of the downloader. // When that process terminates, we look for [cache dir]\ReadyToGo.txt and if it's // there, then we start the job. // -------------------------------------------------------------------------------- // bool StartDownloadingAppFiles( CUtlVector<char*> &newArgv, char *cacheDir, int cacheDirLen, bool bShowAppWindow, HANDLE *hProcess, bool bPatching ) { *hProcess = NULL; V_strncpy( cacheDir, g_FileCachePath, cacheDirLen ); // For now, cache dir is always the same. It's [current directory]\cache. if ( _access( cacheDir, 0 ) != 0 ) { if ( !CreateDirectory( cacheDir, NULL ) && GetLastError() != ERROR_ALREADY_EXISTS ) { Warning( "Unable to create cache directory: %s.\n", cacheDir ); return false; } } // Clear all the files in the directory. char searchStr[MAX_PATH]; V_ComposeFileName( cacheDir, "*.*", searchStr, sizeof( searchStr ) ); _finddata_t findData; intptr_t ret = _findfirst( searchStr, &findData ); if ( ret != -1 ) { do { if ( findData.name[0] == '.' ) continue; char fullFilename[MAX_PATH]; V_ComposeFileName( cacheDir, findData.name, fullFilename, sizeof( fullFilename ) ); if ( _unlink( fullFilename ) != 0 ) { Warning( "_unlink( %s ) failed.\n", fullFilename ); return false; } } while ( _findnext( ret, &findData ) == 0 ); _findclose( ret ); } // Change the EXE name to an absolute path to exactly where it is in the cache directory. int maxExeNameLen = 1024; char *pExeName = new char[maxExeNameLen]; if ( bPatching ) { V_ComposeFileName( cacheDir, "vmpi_service_install.exe", pExeName, maxExeNameLen ); // Add args for the installer. newArgv.InsertAfter( 0, CopyString( "-DontTouchUI" ) ); // When patching, we can't start the UI and the installer can't because we're running in the local system account // and the UI is running on the account of whoever logged in. So what we do is send a message to the UI telling it // to run <cacheDir>\WaitAndRestart and restart itself in N seconds. newArgv.InsertAfter( 0, CopyString( "-Install_Quiet" ) ); } else { V_ComposeFileName( cacheDir, newArgv[0], pExeName, maxExeNameLen ); } delete newArgv[0]; newArgv[0] = pExeName; char fullExeFilename[MAX_PATH]; V_ComposeFileName( g_BaseAppPath, "vmpi_transfer.exe", fullExeFilename, sizeof( fullExeFilename ) ); CUtlVector<char*> downloaderArgs; downloaderArgs.AddToTail( fullExeFilename ); #if defined( _DEBUG ) downloaderArgs.AddToTail( "-allowdebug" ); #endif downloaderArgs.AddToTail( "-CachePath" ); // Tell it where to download the files to. downloaderArgs.AddToTail( cacheDir ); // Pass all the -mpi_worker, -mpi_file, -mpi_filebase args into the downloader app. for ( int i=1; i < (int)newArgv.Count()-1; i++ ) { if ( V_stricmp( newArgv[i], "-mpi_filebase" ) == 0 || V_stricmp( newArgv[i], "-mpi_file" ) == 0 ) { downloaderArgs.AddToTail( newArgv[i] ); downloaderArgs.AddToTail( newArgv[i+1] ); newArgv.Remove( i ); newArgv.Remove( i ); --i; } else if ( V_stricmp( newArgv[i], "-mpi_worker" ) == 0 ) { // We need this arg so it knows what IP to connect to, but we want to leave it in the final launch args too. downloaderArgs.AddToTail( newArgv[i] ); downloaderArgs.AddToTail( newArgv[i+1] ); ++i; } } // Transfer each file. PROCESS_INFORMATION pi; if ( !RunProcessFromArgs( downloaderArgs, bShowAppWindow, false, g_BaseAppPath, &pi ) ) return false; *hProcess = pi.hProcess; return true; }