async Task OnCommandAsync(ArraySegment <byte> commandBuffer, WebSocket webSocket) { try { var listenerCommand = ListenerCommand.ReadObject(commandBuffer); if (listenerCommand.Accept != null) { // Don't block the pump waiting for the rendezvous this.OnAcceptCommandAsync(listenerCommand.Accept).Fork(this); } else if (listenerCommand.Request != null) { await HybridHttpConnection.CreateAsync(this, listenerCommand.Request, webSocket).ConfigureAwait(false); } else { string json = Encoding.UTF8.GetString( commandBuffer.Array, commandBuffer.Offset, Math.Min(commandBuffer.Count, HybridConnectionConstants.MaxUnrecognizedJson)); RelayEventSource.Log.Warning(this, $"Received an unknown command: {json}."); } } catch (Exception exception) when(!Fx.IsFatal(exception)) { RelayEventSource.Log.HandledExceptionAsWarning(this, exception); } }
async Task SendResponseAsync(ListenerCommand.ResponseCommand responseCommand, Stream responseBodyStream, CancellationToken cancelToken) { if (this.rendezvousWebSocket == null) { RelayEventSource.Log.HybridHttpConnectionSendResponse(this.TrackingContext, "control", responseCommand.StatusCode); var listenerCommand = new ListenerCommand { Response = responseCommand }; await this.listener.SendControlCommandAndStreamAsync(listenerCommand, responseBodyStream, cancelToken).ConfigureAwait(false); } else { RelayEventSource.Log.HybridHttpConnectionSendResponse(this.TrackingContext, "rendezvous", responseCommand.StatusCode); await this.EnsureRendezvousAsync(cancelToken).ConfigureAwait(false); using (var memoryStream = new MemoryStream(this.listener.ConnectionBufferSize)) { new ListenerCommand { Response = responseCommand }.WriteObject(memoryStream); memoryStream.Position = 0; ArraySegment <byte> buffer = memoryStream.GetArraySegment(); // We need to respond over the rendezvous connection await this.rendezvousWebSocket.SendAsync(buffer, WebSocketMessageType.Text, true, cancelToken).ConfigureAwait(false); if (responseCommand.Body && responseBodyStream != null) { buffer = new ArraySegment <byte>(buffer.Array, 0, buffer.Array.Length); await this.rendezvousWebSocket.SendStreamAsync(responseBodyStream, WebSocketMessageType.Binary, buffer, cancelToken).ConfigureAwait(false); } } } }
void OnCommand(ArraySegment <byte> buffer) { try { ListenerCommand listenerCommand; using (var stream = new MemoryStream(buffer.Array, buffer.Offset, buffer.Count)) { listenerCommand = ListenerCommand.ReadObject(stream); } if (listenerCommand.Accept != null) { this.OnAcceptClientCommand(listenerCommand.Accept).Fork(this); } else { string json = Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count); RelayEventSource.Log.RelayListenerUnknownCommand(this.ToString(), json); } } catch (Exception exception) when(!Fx.IsFatal(exception)) { RelayEventSource.Log.HandledExceptionAsWarning(this, exception); } }
async Task OnCommandAsync(ArraySegment <byte> buffer) { try { ListenerCommand listenerCommand; using (var stream = new MemoryStream(buffer.Array, buffer.Offset, buffer.Count)) { listenerCommand = ListenerCommand.ReadObject(stream); } if (listenerCommand.Accept != null) { await this.OnAcceptClientCommandAsync(listenerCommand.Accept).ConfigureAwait(false); } else { string json = Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count); RelayEventSource.Log.RelayListenerUnknownCommand(this.ToString(), json); } } catch (Exception exception) { if (Fx.IsFatal(exception)) { throw; } RelayEventSource.Log.HandledExceptionAsWarning(this, exception); } }
public static ListenerCommand ReadObject(ArraySegment <byte> buffer) { using (var stream = new MemoryStream(buffer.Array, buffer.Offset, buffer.Count)) { return(ListenerCommand.ReadObject(stream)); } }
async void OnTokenRenewed(object sender, TokenEventArgs eventArgs) { try { var listenerCommand = new ListenerCommand(); listenerCommand.RenewToken = new ListenerCommand.RenewTokenCommand(); listenerCommand.RenewToken.Token = eventArgs.Token.TokenString; await this.SendCommandAsync(listenerCommand, CancellationToken.None).ConfigureAwait(false); } catch (Exception exception) when(!Fx.IsFatal(exception)) { RelayEventSource.Log.HandledExceptionAsWarning(this.listener, exception); } }
internal async Task SendCommandAsync(ListenerCommand listenerCommand, CancellationToken cancellationToken) { Task <WebSocket> connectTask = this.EnsureConnectTask(cancellationToken); var webSocket = await connectTask.ConfigureAwait(false); using (var stream = new MemoryStream()) { listenerCommand.WriteObject(stream); byte[] buffer = stream.GetBuffer(); using (await this.sendLock.LockAsync(cancellationToken).ConfigureAwait(false)) { await webSocket.SendAsync( new ArraySegment <byte>(buffer, 0, (int)stream.Length), WebSocketMessageType.Binary, true, cancellationToken).ConfigureAwait(false); } } }
async Task <RequestCommandAndStream> ReceiveRequestOverRendezvousAsync() { using (var cancelSource = new CancellationTokenSource(this.OperationTimeout)) { // A Rendezvous is required to get full request await this.EnsureRendezvousAsync(cancelSource.Token).ConfigureAwait(false); } RelayEventSource.Log.HybridHttpReadRendezvousValue(this, "request command"); ListenerCommand.RequestCommand requestCommand; using (var rendezvousCommandStream = new WebSocketMessageStream(this.rendezvousWebSocket, this.OperationTimeout)) { // Deserializing the object from stream makes a sync-over-async call which can deadlock // if performed on the websocket transport's callback thread. requestCommand = await Task.Run(() => ListenerCommand.ReadObject(rendezvousCommandStream).Request).ConfigureAwait(false); if (rendezvousCommandStream.MessageType == WebSocketMessageType.Close) { throw RelayEventSource.Log.ThrowingException(new InvalidOperationException(SR.EntityClosedOrAborted), this); } else if (rendezvousCommandStream.MessageType != WebSocketMessageType.Text) { throw RelayEventSource.Log.ThrowingException( new ProtocolViolationException(SR.GetString(SR.InvalidType, WebSocketMessageType.Text, rendezvousCommandStream.MessageType)), this); } else if (requestCommand == null) { throw RelayEventSource.Log.ThrowingException(new ProtocolViolationException(SR.GetString(SR.InvalidType, "request", "{unknown}")), this); } } Stream requestStream = null; if (requestCommand.Body.HasValue && requestCommand.Body.Value) { RelayEventSource.Log.HybridHttpReadRendezvousValue(this, "request body"); requestStream = new WebSocketMessageStream(this.rendezvousWebSocket, this.OperationTimeout); } return(new RequestCommandAndStream(requestCommand, requestStream)); }
internal async Task SendCommandAndStreamAsync(ListenerCommand command, Stream stream, CancellationToken cancelToken) { Task <WebSocket> connectTask = this.EnsureConnectTask(cancelToken); var webSocket = await connectTask.ConfigureAwait(false); using (await this.sendAsyncLock.LockAsync(cancelToken).ConfigureAwait(false)) { // Since we're using the sendBuffer.Array this work needs to be inside the sendAsyncLock. ArraySegment <byte> commandBuffer; using (var commandStream = new MemoryStream(this.sendBuffer.Array, writable: true)) { commandStream.SetLength(0); command.WriteObject(commandStream); commandBuffer = new ArraySegment <byte>(this.sendBuffer.Array, 0, (int)commandStream.Position); } await webSocket.SendAsync(commandBuffer, WebSocketMessageType.Text, true, cancelToken).ConfigureAwait(false); if (stream != null) { await webSocket.SendStreamAsync(stream, WebSocketMessageType.Binary, this.sendBuffer, cancelToken).ConfigureAwait(false); } } }
internal Task SendControlCommandAndStreamAsync(ListenerCommand command, Stream stream, CancellationToken cancelToken) { return(this.controlConnection.SendCommandAndStreamAsync(command, stream, cancelToken)); }
internal void SendControlCommand(ListenerCommand listenerCommand, CancellationToken cancellationToken) { this.controlConnection.SendCommandAsync(listenerCommand, cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult(); }