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(); } }
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()); }