public void ReadWriteRequest()
 {
     Task.Run(async () =>
     {
         var request = new BuildRequest(
             BuildProtocolConstants.ProtocolVersion,
             RequestLanguage.VisualBasicCompile,
             ImmutableArray.Create(
                 new BuildRequest.Argument(BuildProtocolConstants.ArgumentId.CurrentDirectory, argumentIndex: 0, value: "directory"),
                 new BuildRequest.Argument(BuildProtocolConstants.ArgumentId.CommandLineArgument, argumentIndex: 1, value: "file")));
         var memoryStream = new MemoryStream();
         await request.WriteAsync(memoryStream, default(CancellationToken)).ConfigureAwait(false);
         Assert.True(memoryStream.Position > 0);
         memoryStream.Position = 0;
         var read = await BuildRequest.ReadAsync(memoryStream, default(CancellationToken)).ConfigureAwait(false);
         Assert.Equal(BuildProtocolConstants.ProtocolVersion, read.ProtocolVersion);
         Assert.Equal(RequestLanguage.VisualBasicCompile, read.Language);
         Assert.Equal(2, read.Arguments.Length);
         Assert.Equal(BuildProtocolConstants.ArgumentId.CurrentDirectory, read.Arguments[0].ArgumentId);
         Assert.Equal(0, read.Arguments[0].ArgumentIndex);
         Assert.Equal("directory", read.Arguments[0].Value);
         Assert.Equal(BuildProtocolConstants.ArgumentId.CommandLineArgument, read.Arguments[1].ArgumentId);
         Assert.Equal(1, read.Arguments[1].ArgumentIndex);
         Assert.Equal("file", read.Arguments[1].Value);
     }).Wait();
 }
Ejemplo n.º 2
0
            protected override Task<BuildResponse> ServeBuildRequest(BuildRequest request, CancellationToken cancellationToken)
            {
                if (ServeBuildRequestFunc != null)
                {
                    return ServeBuildRequestFunc(request, cancellationToken);
                }

                return base.ServeBuildRequest(request, cancellationToken);
            }
Ejemplo n.º 3
0
        private void VerifyShutdownRequest(BuildRequest request)
        {
            Assert.Equal(1, request.Arguments.Length);

            var argument = request.Arguments[0];
            Assert.Equal(BuildProtocolConstants.ArgumentId.Shutdown, argument.ArgumentId);
            Assert.Equal(0, argument.ArgumentIndex);
            Assert.Equal("", argument.Value);
        }
Ejemplo n.º 4
0
        internal static async Task <BuildResponse> RunServerCompilationCore(
            RequestLanguage language,
            List <string> arguments,
            BuildPathsAlt buildPaths,
            string pipeName,
            string keepAlive,
            string libEnvVariable,
            int?timeoutOverride,
            Func <string, string, bool> tryCreateServerFunc,
            CancellationToken cancellationToken)
        {
            if (pipeName == null)
            {
                return(new RejectedBuildResponse());
            }

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

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

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

                        if (!holdsMutex)
                        {
                            return(new RejectedBuildResponse());
                        }
                    }
                    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))
                {
                    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 = BuildRequest.Create(language,
                                                      buildPaths.WorkingDirectory,
                                                      buildPaths.TempDirectory,
                                                      arguments,
                                                      keepAlive,
                                                      libEnvVariable);

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

            return(new RejectedBuildResponse());
        }
Ejemplo n.º 5
0
        internal static Task <BuildResponse> RunServerCompilationCore(
            RequestLanguage language,
            List <string> arguments,
            BuildPathsAlt buildPaths,
            string pipeName,
            string keepAlive,
            string libEnvVariable,
            int?timeoutOverride,
            Func <string, string, bool> tryCreateServerFunc,
            CancellationToken cancellationToken)
        {
            if (pipeName == null)
            {
                return(Task.FromResult <BuildResponse>(new RejectedBuildResponse()));
            }

            if (buildPaths.TempDirectory == null)
            {
                return(Task.FromResult <BuildResponse>(new RejectedBuildResponse()));
            }

            var  clientDir              = buildPaths.ClientDirectory;
            var  timeoutNewProcess      = timeoutOverride ?? TimeOutMsNewProcess;
            var  timeoutExistingProcess = timeoutOverride ?? TimeOutMsExistingProcess;
            var  clientMutexName        = GetClientMutexName(pipeName);
            bool holdsMutex;

            using (var clientMutex = new Mutex(initiallyOwned: true,
                                               name: clientMutexName,
                                               createdNew: out holdsMutex))
            {
                try
                {
                    if (!holdsMutex)
                    {
                        try
                        {
                            holdsMutex = clientMutex.WaitOne(timeoutNewProcess);

                            if (!holdsMutex)
                            {
                                return(Task.FromResult <BuildResponse>(new RejectedBuildResponse()));
                            }
                        }
                        catch (AbandonedMutexException)
                        {
                            holdsMutex = true;
                        }
                    }

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

                    NamedPipeClientStream pipe = null;

                    if (wasServerRunning || tryCreateServerFunc(clientDir, pipeName))
                    {
                        pipe = TryConnectToServer(pipeName,
                                                  timeout,
                                                  cancellationToken);
                    }

                    if (pipe != null)
                    {
                        var request = BuildRequest.Create(language,
                                                          buildPaths.WorkingDirectory,
                                                          buildPaths.TempDirectory,
                                                          arguments,
                                                          keepAlive,
                                                          libEnvVariable);

                        return(TryCompile(pipe, request, cancellationToken));
                    }
                }
                finally
                {
                    if (holdsMutex)
                    {
                        clientMutex.ReleaseMutex();
                    }
                }
            }

            return(Task.FromResult <BuildResponse>(new RejectedBuildResponse()));
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Try to compile using the server. Returns a null-containing Task if a response
        /// from the server cannot be retrieved.
        /// </summary>
        private static async Task<BuildResponse> TryCompile(NamedPipeClientStream pipeStream,
                                                            BuildRequest request,
                                                            CancellationToken cancellationToken)
        {
            BuildResponse response;
            using (pipeStream)
            {
                // Write the request
                try
                {
                    Log("Begin writing request");
                    await request.WriteAsync(pipeStream, cancellationToken).ConfigureAwait(false);
                    Log("End writing request");
                }
                catch (Exception e)
                {
                    LogException(e, "Error writing build request.");
                    return new RejectedBuildResponse();
                }

                // Wait for the compilation and a monitor to detect if the server disconnects
                var serverCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

                Log("Begin reading response");

                var responseTask = BuildResponse.ReadAsync(pipeStream, serverCts.Token);
                var monitorTask = CreateMonitorDisconnectTask(pipeStream, serverCts.Token);
                await Task.WhenAny(responseTask, monitorTask).ConfigureAwait(false);

                Log("End reading response");

                if (responseTask.IsCompleted)
                {
                    // await the task to log any exceptions
                    try
                    {
                        response = await responseTask.ConfigureAwait(false);
                    }
                    catch (Exception e)
                    {
                        LogException(e, "Error reading response");
                        response = new RejectedBuildResponse();
                    }
                }
                else
                {
                    Log("Server disconnect");
                    response = new RejectedBuildResponse();
                }

                // Cancel whatever task is still around
                serverCts.Cancel();
                Debug.Assert(response != null);
                return response;
            }
        }
Ejemplo n.º 7
0
        internal static async Task <BuildResponse> RunServerCompilationCore(
            RequestLanguage language,
            List <string> arguments,
            BuildPathsAlt buildPaths,
            string pipeName,
            string keepAlive,
            string libEnvVariable,
            int?timeoutOverride,
            CreateServerFunc createServerFunc,
            CancellationToken cancellationToken)
        {
            if (pipeName == null)
            {
                return(new RejectedBuildResponse());
            }

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

            // 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(BuildProtocolConstants.GetCommitHash()))
            {
                return(new IncorrectHashBuildResponse());
            }

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

            try
            {
                var holdsMutex = false;
                try
                {
                    var clientMutexName = GetClientMutexName(pipeName);
                    clientMutex = OpenOrCreateMutex(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 RejectedBuildResponse());
                }

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

                        if (!holdsMutex)
                        {
                            return(new RejectedBuildResponse());
                        }
                    }
                    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 || createServerFunc(clientDir, pipeName))
                {
                    pipeTask = TryConnectToServerAsync(pipeName, timeout, cancellationToken);
                }
            }
            finally
            {
                clientMutex?.Dispose();
            }

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

                if (pipe != null)
                {
                    var request = BuildRequest.Create(language,
                                                      buildPaths.WorkingDirectory,
                                                      buildPaths.TempDirectory,
                                                      BuildProtocolConstants.GetCommitHash(),
                                                      arguments,
                                                      keepAlive,
                                                      libEnvVariable);

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

            return(new RejectedBuildResponse());
        }
Ejemplo n.º 8
0
 protected override void ValidateBuildRequest(BuildRequest request)
 {
     ValidateBuildRequestFunc?.Invoke(request);
 }
Ejemplo n.º 9
0
 internal static async Task<BuildResponse> Send(string pipeName, BuildRequest request)
 {
     using (var client = new NamedPipeClientStream(pipeName))
     {
         await client.ConnectAsync();
         await request.WriteAsync(client);
         return await BuildResponse.ReadAsync(client);
     }
 }
Ejemplo n.º 10
0
        internal static async Task <BuildResponse> RunServerCompilationCoreAsync(
            Guid requestId,
            RequestLanguage language,
            List <string> arguments,
            BuildPathsAlt buildPaths,
            string?pipeName,
            string?keepAlive,
            string?libDirectory,
            int?timeoutOverride,
            CreateServerFunc createServerFunc,
            ICompilerServerLogger logger,
            CancellationToken cancellationToken
            )
        {
            if (pipeName is null)
            {
                throw new ArgumentException(nameof(pipeName));
            }

            if (buildPaths.TempDirectory == null)
            {
                throw new ArgumentException(nameof(buildPaths));
            }

            // 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(BuildProtocolConstants.GetCommitHash()))
            {
                return(new IncorrectHashBuildResponse());
            }

            var pipeTask = tryConnectToServer(
                pipeName,
                buildPaths,
                timeoutOverride,
                createServerFunc,
                logger,
                cancellationToken
                );

            if (pipeTask is null)
            {
                return(new RejectedBuildResponse("Failed to connect to server"));
            }
            else
            {
                using var pipe = await pipeTask.ConfigureAwait(false);

                if (pipe is null)
                {
                    return(new RejectedBuildResponse("Failed to connect to server"));
                }
                else
                {
                    var request = BuildRequest.Create(
                        language,
                        arguments,
                        workingDirectory: buildPaths.WorkingDirectory,
                        tempDirectory: buildPaths.TempDirectory,
                        compilerHash: BuildProtocolConstants.GetCommitHash() ?? "",
                        requestId: requestId,
                        keepAlive: keepAlive,
                        libDirectory: libDirectory
                        );

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