/// <summary> /// Shutting down the server is an inherently racy operation. The server can be started or stopped by /// external parties at any time. /// /// This function will return success if at any time in the function the server is determined to no longer /// be running. /// </summary> internal async Task <int> RunShutdownAsync(string pipeName, bool waitForProcess = true, TimeSpan?timeout = null, CancellationToken cancellationToken = default) { if (WasServerRunning(pipeName) == false) { // The server holds the mutex whenever it is running, if it's not open then the // server simply isn't running. return(CommonCompiler.Succeeded); } try { var realTimeout = timeout != null ? (int)timeout.Value.TotalMilliseconds : Timeout.Infinite; using (var client = await ConnectForShutdownAsync(pipeName, realTimeout).ConfigureAwait(false)) { var request = BuildRequest.CreateShutdown(); await request.WriteAsync(client, cancellationToken).ConfigureAwait(false); var response = await BuildResponse.ReadAsync(client, cancellationToken).ConfigureAwait(false); var shutdownResponse = (ShutdownBuildResponse)response; if (waitForProcess) { try { var process = Process.GetProcessById(shutdownResponse.ServerProcessId); process.WaitForExit(); } catch (Exception) { // There is an inherent race here with the server process. If it has already shutdown // by the time we try to access it then the operation has succeed. } } } return(CommonCompiler.Succeeded); } catch (Exception) { if (WasServerRunning(pipeName) == false) { // If the server was in the process of shutting down when we connected then it's reasonable // for an exception to happen. If the mutex has shutdown at this point then the server // is shut down. return(CommonCompiler.Succeeded); } return(CommonCompiler.Failed); } }
private Task <BuildResponse> ServeBuildRequest(BuildRequest request, CancellationToken cancellationToken) { return(Task.Run(() => { try { // Do the compilation Log("Begin compilation"); BuildResponse response = _handler.HandleRequest(request, cancellationToken); Log("End compilation"); return response; } catch (Exception e) when(FatalError.Report(e)) { throw ExceptionUtilities.Unreachable; } })); }
private static int HandleResponse(BuildResponse response) { if (response.Type == BuildResponse.ResponseType.Completed) { var completedResponse = (CompletedBuildResponse)response; return ConsoleUtil.RunWithOutput( completedResponse.Utf8Output, (outWriter, errorWriter) => { outWriter.Write(completedResponse.Output); errorWriter.Write(completedResponse.ErrorOutput); return completedResponse.ReturnCode; }); } else { Console.Error.WriteLine(CommandLineParser.MismatchedVersionErrorText); return CommonCompiler.Failed; } }
private async Task <CompletionData> WriteBuildResponseAsync( IClientConnection clientConnection, Guid requestId, BuildResponse response, CompletionData completionData, CancellationToken cancellationToken ) { var message = response switch { RejectedBuildResponse r => $"Writing {r.Type} response '{r.Reason}' for {requestId}", _ => $"Writing {response.Type} response for {requestId}" }; Logger.Log(message); await clientConnection .WriteBuildResponseAsync(response, cancellationToken) .ConfigureAwait(false); return(completionData); }
public Task WriteBuildResponse(BuildResponse response, CancellationToken cancellationToken) { return(response.WriteAsync(_pipeStream, cancellationToken)); }
public async Task ServeConnection() { BuildRequest request; try { Log("Begin reading request"); request = await BuildRequest.ReadAsync(pipeStream, cancellationTokenSource.Token).ConfigureAwait(false); Log("End reading request"); } catch (IOException e) { LogException(e, "Reading request from named pipe."); FinishConnection(CompletionReason.IOFailure); return; } catch (OperationCanceledException e) { LogException(e, "Reading request from named pipe."); FinishConnection(CompletionReason.Cancelled); return; } if (!ClientAndOurIdentitiesMatch(pipeStream)) { Log("Client identity doesn't match."); FinishConnection(CompletionReason.SecurityViolation); return; } CheckForNewKeepAlive(request); // Start a monitor that cancels if the pipe closes on us var _ = MonitorPipeForDisconnection().ConfigureAwait(false); // Do the compilation Log("Begin compilation"); BuildResponse response = await Task.Run(() => { try { return(handler.HandleRequest(request, cancellationTokenSource.Token)); } catch (Exception e) if (CompilerFatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }).ConfigureAwait(false); Log("End compilation"); try { Log("Begin writing response"); await response.WriteAsync(pipeStream, cancellationTokenSource.Token).ConfigureAwait(false); Log("End writing response"); } catch (IOException e) { LogException(e, "Writing response to named pipe."); FinishConnection(CompletionReason.IOFailure); return; } catch (OperationCanceledException e) { LogException(e, "Writing response to named pipe."); FinishConnection(CompletionReason.Cancelled); return; } Log("Completed writing response to named pipe."); FinishConnection(CompletionReason.Success); }
private static int HandleResponse(BuildResponse response, string clientDir, string sdkDir, IAnalyzerAssemblyLoader analyzerLoader, Func<string, string, string[], IAnalyzerAssemblyLoader, int> fallbackCompiler, List<string> parsedArgs) { switch (response.Type) { case BuildResponse.ResponseType.MismatchedVersion: Console.Error.WriteLine(CommandLineParser.MismatchedVersionErrorText); return CommonCompiler.Failed; case BuildResponse.ResponseType.Completed: var completedResponse = (CompletedBuildResponse)response; return ConsoleUtil.RunWithOutput( completedResponse.Utf8Output, (outWriter, errorWriter) => { outWriter.Write(completedResponse.Output); errorWriter.Write(completedResponse.ErrorOutput); return completedResponse.ReturnCode; }); case BuildResponse.ResponseType.AnalyzerInconsistency: return fallbackCompiler(clientDir, sdkDir, parsedArgs.ToArray(), analyzerLoader); default: throw new InvalidOperationException("Encountered unknown response type"); } }
/// <summary> /// Handle a response from the server, reporting messages and returning /// the appropriate exit code. /// </summary> private int HandleResponse(BuildResponse response, string pathToTool, string responseFileCommands, string commandLineCommands) { switch (response.Type) { case BuildResponse.ResponseType.MismatchedVersion: LogErrorOutput(CommandLineParser.MismatchedVersionErrorText); return -1; case BuildResponse.ResponseType.Completed: var completedResponse = (CompletedBuildResponse)response; LogMessages(completedResponse.Output, StandardOutputImportanceToUse); if (LogStandardErrorAsError) { LogErrorOutput(completedResponse.ErrorOutput); } else { LogMessages(completedResponse.ErrorOutput, StandardErrorImportanceToUse); } return completedResponse.ReturnCode; case BuildResponse.ResponseType.AnalyzerInconsistency: return base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands); default: throw new InvalidOperationException("Encountered unknown response type"); } }
public Task WriteBuildResponseAsync(BuildResponse response, CancellationToken cancellationToken) => response.WriteAsync(Stream, cancellationToken);
public Task WriteBuildResponse(BuildResponse response, CancellationToken cancellationToken) { return response.WriteAsync(_pipeStream, cancellationToken); }
/// <summary> /// Shutting down the server is an inherently racy operation. The server can be started or stopped by /// external parties at any time. /// /// This function will return success if at any time in the function the server is determined to no longer /// be running. /// </summary> internal static async Task <int> RunShutdownAsync(string pipeName, bool waitForProcess = true, TimeSpan?timeout = null, CancellationToken cancellationToken = default(CancellationToken)) { if (string.IsNullOrEmpty(pipeName)) { var clientDirectory = AppDomain.CurrentDomain.BaseDirectory; pipeName = DesktopBuildClient.GetPipeNameFromFileInfo(clientDirectory); } var mutexName = BuildProtocolConstants.GetServerMutexName(pipeName); if (!DesktopBuildClient.WasServerMutexOpen(mutexName)) { // The server holds the mutex whenever it is running, if it's not open then the // server simply isn't running. return(CommonCompiler.Succeeded); } try { using (var client = new NamedPipeClientStream(pipeName)) { var realTimeout = timeout != null ? (int)timeout.Value.TotalMilliseconds : Timeout.Infinite; client.Connect(realTimeout); var request = BuildRequest.CreateShutdown(); await request.WriteAsync(client, cancellationToken).ConfigureAwait(false); var response = await BuildResponse.ReadAsync(client, cancellationToken).ConfigureAwait(false); var shutdownResponse = (ShutdownBuildResponse)response; if (waitForProcess) { try { var process = Process.GetProcessById(shutdownResponse.ServerProcessId); process.WaitForExit(); } catch (Exception) { // There is an inherent race here with the server process. If it has already shutdown // by the time we try to access it then the operation has succeed. } } } return(CommonCompiler.Succeeded); } catch (Exception) { if (!DesktopBuildClient.WasServerMutexOpen(mutexName)) { // If the server was in the process of shutting down when we connected then it's reasonable // for an exception to happen. If the mutex has shutdown at this point then the server // is shut down. return(CommonCompiler.Succeeded); } return(CommonCompiler.Failed); } }