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