private static string AskServerForUpdate(UpdateCheckRequest requestData) { int currentBuildNumber = Assembly.GetExecutingAssembly().GetName().Version.Revision; string clientGuid = string.Empty; if (requestData != null && requestData.ClientGuid != null) { clientGuid = requestData.ClientGuid; } bool requestIsFromService = false; if (requestData != null) { requestIsFromService = requestData.RequestIsFromService; } // Do initial HTTP GET request var request = (HttpWebRequest)WebRequest.Create( String.Format(k_updateUrl, currentBuildNumber, clientGuid, requestIsFromService)); request.KeepAlive = false; try { using (var responseObject = request.GetResponse()) using (var responseReader = new StreamReader(responseObject.GetResponseStream())) { return(responseReader.ReadToEnd()); } } catch (Exception e) { ExecuteDelegateSwallowExceptions(requestData.LogWarningHandler, "Exception while trying to check for update info.", e); return(null); } }
private static void SafeLogMessage(object requestDataObject, string logMessage) { UpdateCheckRequest requestData = (requestDataObject as UpdateCheckRequest); if (requestData != null && requestData.LogMessageHandler != null) { ExecuteDelegateSwallowExceptions(requestData.LogMessageHandler, logMessage); } }
internal static void ForceUpdateCheckNow(UpdateCheckRequest requestData, bool resetTimer) { if (resetTimer) { s_checkTimer.Change(TimeSpan.Zero, TimeSpan.FromHours(24)); } else { CheckForAndRunUpdates(requestData); } }
internal static void StartUpdateCheckerTimer(UpdateCheckRequest requestData) { var timeUntilFirstCheck = new TimeSpan((long)(TimeSpan.FromHours(24).Ticks *new Random().NextDouble())); if (IsImmediateUpdateCheckFlagSet()) { timeUntilFirstCheck = TimeSpan.FromSeconds(10); SafeLogMessage(requestData, "ImmediateUpdateCheck flag is set, but will be subjugated to user preference for automatic updates."); } s_checkTimer = new System.Threading.Timer(CheckForAndRunUpdates_FromTimer, requestData, timeUntilFirstCheck, TimeSpan.FromHours(24)); SafeLogMessage(requestData, AreAutomaticUpdatesEnabled() ? "Automatic updates are enabled" : "Automatic updates are disabled (by user)"); SafeLogMessage(requestData, String.Format( "First update check (if enabled) scheduled for t-minus {0} hours", timeUntilFirstCheck.TotalHours)); }
private static string AskServerForUpdate(UpdateCheckRequest requestData) { int currentBuildNumber = Assembly.GetExecutingAssembly().GetName().Version.Revision; string clientGuid = string.Empty; if (requestData != null && requestData.ClientGuid != null) { clientGuid = requestData.ClientGuid; } bool requestIsFromService = false; if (requestData != null) { requestIsFromService = requestData.RequestIsFromService; } // Do initial HTTP GET request var request = (HttpWebRequest)WebRequest.Create( String.Format(k_updateUrl, currentBuildNumber, clientGuid, requestIsFromService)); request.KeepAlive = false; try { using (var responseObject = request.GetResponse()) using (var responseReader = new StreamReader(responseObject.GetResponseStream())) { return responseReader.ReadToEnd(); } } catch (Exception e) { ExecuteDelegateSwallowExceptions(requestData.LogWarningHandler, "Exception while trying to check for update info.", e); return null; } }
internal static void StartUpdateCheckerTimer(UpdateCheckRequest requestData) { var timeUntilFirstCheck = new TimeSpan((long)(TimeSpan.FromHours(24).Ticks * new Random().NextDouble())); if (IsImmediateUpdateCheckFlagSet()) { timeUntilFirstCheck = TimeSpan.FromSeconds(10); SafeLogMessage(requestData, "ImmediateUpdateCheck flag is set, but will be subjugated to user preference for automatic updates."); } s_checkTimer = new System.Threading.Timer(CheckForAndRunUpdates_FromTimer, requestData, timeUntilFirstCheck, TimeSpan.FromHours(24)); SafeLogMessage(requestData, AreAutomaticUpdatesEnabled() ? "Automatic updates are enabled" : "Automatic updates are disabled (by user)"); SafeLogMessage(requestData, String.Format( "First update check (if enabled) scheduled for t-minus {0} hours", timeUntilFirstCheck.TotalHours)); }
// Note: could block for a while, but will execute on a ThreadPool thread. // // Note 2: don't let exceptions bubble past the scope of this function, or else bad things // will happen since it's a ThreadPool thread on .NET 2.0. // // Note 3: this function in theory should be reentrant, but is not since it's unlikely any // single execution will last for longer than 24 hours (the time for subsequent // invocations). // // Note 4: it could also be reentrant if the server commands ForceCheckForUpdates(), but that // is also unlikely. private static void CheckForAndRunUpdates(object requestDataObject) { UpdateCheckRequest requestData = null; try { requestData = (requestDataObject as UpdateCheckRequest ?? new UpdateCheckRequest()); // try to download update info var updateInfoXml = AskServerForUpdate(requestData); if (string.IsNullOrEmpty(updateInfoXml)) { return; } // decode and verify update info var verifiedUpdateInfo = VerifiedUpdateInfo.FromUpdateXml(updateInfoXml, (requestData == null ? false : requestData.AcceptTestCertificate)); // try to download update executable var downloadFileDir = LibraryIO.FindWritableDirectory(CommonDirectories.CurrentExecutingDirectory, CommonDirectories.LocalAppData, CommonDirectories.Temp); if (downloadFileDir == null) { throw new Exception("Cannot find writable directory for update download."); } var downloadFilePath = Path.Combine(downloadFileDir, "DesktopBootstrapUpdater.exe"); if (File.Exists(downloadFilePath)) { try { File.Delete(downloadFilePath); } catch (IOException ioe) { // this is probably an old update that didn't terminate for some reason. try to kill it. SafeLogMessage(requestData, "An updater seems to be running already. Trying to kill it..."); int nKilled = 0; foreach (var runningUpdater in Process.GetProcessesByName("DesktopBootstrapUpdater")) { runningUpdater.Kill(); nKilled++; } SafeLogMessage(requestData, String.Format("Killed {0} already-running updaters", nKilled)); } } using (var webClient = new WebClient()) { webClient.DownloadFile(verifiedUpdateInfo.DownloadUrl, downloadFilePath); } // verify downloaded file hash string downloadedFileHashBase64; using (var fileReader = new FileStream(downloadFilePath, FileMode.Open, FileAccess.Read)) { downloadedFileHashBase64 = Convert.ToBase64String(new SHA1CryptoServiceProvider().ComputeHash(fileReader)); } if (downloadedFileHashBase64 != verifiedUpdateInfo.DownloadHash) { throw new Exception("Updater executable hash is mismatched."); } // we're about the run the updater. if it sees fit it will TerminateProcess() us, which can // leave the tray icon laying behind well after we're gone, sometimes resulting in multiple // DesktopBootstrap icons in the system tray. so instead we're going to hide our tray icon for // a little bit, in case the updater wants to kill us (ha!). // // note, if this update code is executing on DesktopBootstrap.exe, the icon will just be hidden. // if it's being ran from the service, then DesktopBootstrap.exe will be asked to close gracefully, // which should remove the tray icon BUT if the update doesn't restart DesktopBootstrap.exe then it // won't be restarted until the next machine reboot. try { if (requestData.BeforeExecutingUpdateFile != null) { requestData.BeforeExecutingUpdateFile(); } } catch (Exception eBeforeExecuting) { if (requestData != null && requestData.LogWarningHandler != null) { ExecuteDelegateSwallowExceptions(requestData.LogWarningHandler, "Exception calling BeforeExecutingUpdateFile delegate", eBeforeExecuting); } } SafeLogMessage(requestData, String.Format("Launching update executable {0}", downloadFilePath)); Process.Start(downloadFilePath); } catch (Exception e) { if (requestData != null && requestData.LogErrorHandler != null) { ExecuteDelegateSwallowExceptions(requestData.LogErrorHandler, "Exception while checking for and running updates", e); } } }