/// <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;
         }
     }));
 }
示例#3
0
 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;
     }
 }
示例#4
0
        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);
        }
示例#5
0
 public Task WriteBuildResponse(BuildResponse response, CancellationToken cancellationToken)
 {
     return(response.WriteAsync(_pipeStream, cancellationToken));
 }
示例#6
0
            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);
            }
示例#7
0
        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");
            }
        }
示例#8
0
        /// <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);
 }
示例#11
0
        /// <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);
            }
        }