private async Task RunNamedPipeServerAsync()

in sources/Google.Solutions.IapDesktop.Application/Host/SingletonApplicationBase.cs [255:374]


        private async Task RunNamedPipeServerAsync(CancellationToken token)
        {
            var pipeSecurity = new PipeSecurity();
            pipeSecurity.AddAccessRule(
                new PipeAccessRule(
                    WindowsIdentity.GetCurrent().Owner,
                    PipeAccessRights.FullControl,
                    AccessControlType.Allow));

            while (true)
            {
                try
                {
                    //
                    // Sequentially dispatch client connections. 
                    //
                    using (var pipe = new NamedPipeServerStream(
                        this.PipeName,
                        PipeDirection.InOut,
                        1,  // Translates to FILE_FLAG_FIRST_PIPE_INSTANCE
                        PipeTransmissionMode.Message,
                        PipeOptions.None,
                        0,
                        0,
                        pipeSecurity))
                    {
                        await pipe
                            .WaitForConnectionAsync(token)
                            .ConfigureAwait(false);

                        //
                        // The server expects:
                        // IN: <int32> number of arguments
                        // IN: <string> argument #n
                        // IN:  (repeat...)
                        // OUT: return code
                        // OUT: process ID
                        //

                        try
                        {
                            var reader = new BinaryReader(pipe);
                            var writer = new BinaryWriter(pipe);

                            var argsCount = reader.ReadInt32();
                            var args = new string[argsCount];
                            for (var i = 0; i < argsCount; i++)
                            {
                                args[i] = reader.ReadString();
                            }

                            try
                            {
                                var result = HandleSubsequentInvocation(args);
                                writer.Write(result);
                            }
                            catch (TimeoutException)
                            {
                                //
                                // Notify other instance, but don't crash.
                                //
                                writer.Write(-2);
                            }
                            catch (Exception e)
                            {
                                //
                                // Something bad happened, crash.
                                //
                                HandleSubsequentInvocationException(e);
                                writer.Write(-1);
                            }

                            writer.Write(Process.GetCurrentProcess().Id);
                        }
                        catch (IOException)
                        {
                            //
                            // The client closed the pipe early, ignore.
                            //
                        }
                        finally
                        {
                            try
                            {
                                pipe.WaitForPipeDrain();
                            }
                            catch (IOException)
                            {
                                //
                                // The client closed the pipe early, ignore.
                                //
                            }

                            pipe.Disconnect();
                        }
                    }
                }
                catch (TaskCanceledException)
                {
                    return;
                }
                catch (IOException e) when (e.HResult == E_PIPE_BUSY)
                {
                    //
                    // Because we always disconnect the pipe, this shouldn't
                    // normally happen.
                    //
                    // Back off and retry.
                    //
                    ApplicationTraceSource.Log.TraceWarning(
                        "Pipe {0} is busy, retrying", this.PipeName);

                    await Task.Delay(500);
                }
                catch (IOException e)
                {
                    HandleSubsequentInvocationException(e);
                }
            }
        }