/// <summary> /// Fire and forget close /// </summary> public override async Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) { if (_state == WebSocketState.Open) { _state = WebSocketState.Closed; // set this before we write to the network because the write may fail using (MemoryStream stream = _recycledStreamFactory()) { ArraySegment <byte> buffer = BuildClosePayload(closeStatus, statusDescription); WebSocketFrameWriter.Write(WebSocketOpCode.ConnectionClose, buffer, stream, true, _isClient); Events.Log.CloseOutputNoHandshake(_guid, closeStatus, statusDescription); Events.Log.SendingFrame(_guid, WebSocketOpCode.ConnectionClose, true, buffer.Count, true); await WriteStreamToNetwork(stream, cancellationToken); } } else { Events.Log.InvalidStateBeforeCloseOutput(_guid, _state); } // cancel pending reads _internalReadCts.Cancel(); }
/// <summary> /// Called when a Close frame is received /// Send a response close frame if applicable /// </summary> private async Task <WebSocketReceiveResult> RespondToCloseFrame(WebSocketFrame frame, ArraySegment <byte> buffer, CancellationToken token) { _closeStatus = frame.CloseStatus; _closeStatusDescription = frame.CloseStatusDescription; if (_state == WebSocketState.CloseSent) { // this is a response to close handshake initiated by this instance _state = WebSocketState.Closed; Events.Log.CloseHandshakeComplete(_guid); } else if (_state == WebSocketState.Open) { // do not echo the close payload back to the client, there is no requirement for it in the spec. // However, the same CloseStatus as recieved should be sent back. var closePayload = new ArraySegment <byte>(new byte[0], 0, 0); _state = WebSocketState.CloseReceived; Events.Log.CloseHandshakeRespond(_guid, frame.CloseStatus, frame.CloseStatusDescription); using (var stream = _recycledStreamFactory()) { WebSocketFrameWriter.Write(WebSocketOpCode.ConnectionClose, closePayload, stream, true, _isClient); Events.Log.SendingFrame(_guid, WebSocketOpCode.ConnectionClose, true, closePayload.Count, false); await WriteStreamToNetwork(stream, token); } } else { Events.Log.CloseFrameReceivedInUnexpectedState(_guid, _state, frame.CloseStatus, frame.CloseStatusDescription); } return(new WebSocketReceiveResult(frame.Count, WebSocketMessageType.Close, frame.IsFinBitSet, frame.CloseStatus, frame.CloseStatusDescription)); }