public async Task <BuildRequest> ReadBuildRequestAsync(CancellationToken cancellationToken) { var request = await BuildRequest.ReadAsync(Stream, cancellationToken).ConfigureAwait(false); // Now that we've read data from the stream we can validate the identity. if (!NamedPipeUtil.CheckClientElevationMatches(Stream)) { throw new Exception("Client identity does not match server identity."); } // The result is deliberately discarded here. The idea is to kick off the monitor code and // when it completes it will trigger the task. Don't want to block on that here. _ = MonitorDisconnect(); return(request); async Task MonitorDisconnect() { try { await BuildServerConnection.MonitorDisconnectAsync(Stream, request.RequestId, Logger, DisconnectCancellationTokenSource.Token).ConfigureAwait(false); } catch (Exception ex) { Logger.LogException(ex, $"Error monitoring disconnect {request.RequestId}"); } finally { DisconnectTaskCompletionSource.TrySetResult(this); } } }
/// <summary> /// The IsConnected property on named pipes does not detect when the client has disconnected /// if we don't attempt any new I/O after the client disconnects. We start an async I/O here /// which serves to check the pipe for disconnection. /// /// This will return true if the pipe was disconnected. /// </summary> private Task MonitorDisconnectAsync(CancellationToken cancellationToken) { return(BuildServerConnection.MonitorDisconnectAsync(_stream, LoggingIdentifier, cancellationToken)); }