コード例 #1
0
        public async Task <ConnectionData> HandleConnection(bool allowCompilationRequests = true, CancellationToken cancellationToken = default(CancellationToken))
        {
            try
            {
                GenerationRequest request;
                try
                {
                    Log("Begin reading request.");
                    request = await GenerationRequest.ReadAsync(_stream, cancellationToken).ConfigureAwait(false);

                    ValidateGenerationRequest(request);
                    Log("End reading request.");
                }
                catch (Exception e)
                {
                    LogException(e, "Error reading build request.");
                    return(new ConnectionData(CompletionReason.CompilationNotStarted));
                }

                if (request.ProtocolVersion != GenerationProtocolConstants.ProtocolVersion)
                {
                    return(await HandleMismatchedVersionRequest(cancellationToken).ConfigureAwait(false));
                }
                else if (!string.Equals(request.CompilerHash, GenerationProtocolConstants.GetCommitHash(), StringComparison.OrdinalIgnoreCase))
                {
                    return(await HandleIncorrectHashRequest(cancellationToken).ConfigureAwait(false));
                }
                else if (IsShutdownRequest(request))
                {
                    return(await HandleShutdownRequest(cancellationToken).ConfigureAwait(false));
                }
                else if (!allowCompilationRequests)
                {
                    return(await HandleRejectedRequest(cancellationToken).ConfigureAwait(false));
                }
                else
                {
                    return(await HandleCompilationRequest(request, cancellationToken).ConfigureAwait(false));
                }
            }
            finally
            {
                Close();
            }
        }
コード例 #2
0
        internal static async Task <GenerationResponse> RunServerGenerationCore(
            List <string> arguments,
            GenerationsPathsInfo buildPaths,
            string pipeName,
            string keepAlive,
            int?timeoutOverride,
            Func <string, string, bool, bool> tryCreateServerFunc,
            CancellationToken cancellationToken)
        {
            if (pipeName == null)
            {
                return(new RejectedGenerationResponse());
            }

            if (buildPaths.TempDirectory == null)
            {
                return(new RejectedGenerationResponse());
            }

            // early check for the build hash. If we can't find it something is wrong; no point even trying to go to the server
            if (string.IsNullOrWhiteSpace(GenerationProtocolConstants.GetCommitHash()))
            {
                return(new IncorrectHashGenerationResponse());
            }

            var clientDir                         = buildPaths.ClientDirectory;
            var timeoutNewProcess                 = timeoutOverride ?? TimeOutMsNewProcess;
            var timeoutExistingProcess            = timeoutOverride ?? TimeOutMsExistingProcess;
            Task <NamedPipeClientStream> pipeTask = null;
            Mutex clientMutex                     = null;
            var   holdsMutex                      = false;

            try
            {
                try
                {
                    var clientMutexName = GetClientMutexName(pipeName);
                    clientMutex = new Mutex(initiallyOwned: true, name: clientMutexName, out holdsMutex);
                }
                catch
                {
                    // The Mutex constructor can throw in certain cases. One specific example is docker containers
                    // where the /tmp directory is restricted. In those cases there is no reliable way to execute
                    // the server and we need to fall back to the command line.
                    //
                    // Example: https://github.com/dotnet/roslyn/issues/24124
                    return(new RejectedGenerationResponse());
                }

                if (!holdsMutex)
                {
                    try
                    {
                        holdsMutex = clientMutex.WaitOne(timeoutNewProcess);

                        if (!holdsMutex)
                        {
                            return(new RejectedGenerationResponse());
                        }
                    }
                    catch (AbandonedMutexException)
                    {
                        holdsMutex = true;
                    }
                }

                // Check for an already running server
                var  serverMutexName  = GetServerMutexName(pipeName);
                bool wasServerRunning = WasServerMutexOpen(serverMutexName);
                var  timeout          = wasServerRunning ? timeoutExistingProcess : timeoutNewProcess;

                if (wasServerRunning || tryCreateServerFunc(clientDir, pipeName, false))
                {
                    pipeTask = TryConnectToServerAsync(pipeName, timeout, cancellationToken);
                }
            }
            finally
            {
                if (clientMutex != null)
                {
                    if (holdsMutex)
                    {
                        clientMutex.ReleaseMutex();
                    }
                    clientMutex.Dispose();
                }
            }

            if (pipeTask != null)
            {
                var pipe = await pipeTask.ConfigureAwait(false);

                if (pipe != null)
                {
                    var request = GenerationRequest.Create(buildPaths.WorkingDirectory,
                                                           buildPaths.TempDirectory,
                                                           GenerationProtocolConstants.GetCommitHash(),
                                                           arguments,
                                                           keepAlive);

                    return(await TryGeneration(pipe, request, cancellationToken).ConfigureAwait(false));
                }
            }

            return(new RejectedGenerationResponse());
        }