Beispiel #1
0
        /// Called when a Close frame is received, sends a response close frame if applicable
        private WebSocketReceiveResult RespondToCloseFrame(WebSocketFrame frame, ArraySegment <byte> buffer)
        {
            _closeStatus            = frame.CloseStatus;
            _closeStatusDescription = frame.CloseStatusDescription;

            if (_state == WebSocketState.CloseSent)
            {
                // this is a response to close handshake initiated by this instance
                _state = WebSocketState.Closed;
            }
            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.
                ArraySegment <byte> closePayload = new ArraySegment <byte>(new byte[0], 0, 0);
                _state = WebSocketState.CloseReceived;

                using (MemoryStream stream = _recycledStreamFactory())
                {
                    WebSocketFrameWriter.Write(WebSocketOpCode.ConnectionClose, closePayload, stream, true, _isClient);
                    WriteStreamToNetwork(stream);
                }
            }

            return(new WebSocketReceiveResult(frame.Count, WebSocketMessageType.Close, frame.IsFinBitSet, frame.CloseStatus, frame.CloseStatusDescription));
        }
Beispiel #2
0
        /// NOTE: pong payload must be 125 bytes or less
        /// Pong should contain the same payload as the ping
        private void SendPong(ArraySegment <byte> payload)
        {
            // as per websocket spec
            if (payload.Count > MAX_PING_PONG_PAYLOAD_LEN)
            {
                Exception ex = new InvalidOperationException($"Max ping message size {MAX_PING_PONG_PAYLOAD_LEN} exceeded: {payload.Count}");
                CloseOutputAutoTimeout(WebSocketCloseStatus.ProtocolError, ex.Message, ex);
                throw ex;
            }

            try
            {
                if (_state == WebSocketState.Open)
                {
                    using (MemoryStream stream = _recycledStreamFactory())
                    {
                        WebSocketFrameWriter.Write(WebSocketOpCode.Pong, payload, stream, true, _isClient);
                        _logger(LogLevel.Debug, $"websocket.Pong: {payload.Count}");
                        WriteStreamToNetwork(stream);
                    }
                }
            }
            catch (Exception ex)
            {
                CloseOutputAutoTimeout(WebSocketCloseStatus.EndpointUnavailable, "Unable to send Pong response", ex);
                throw;
            }
        }
Beispiel #3
0
        /// Send data to the web socket
        public void Send(ArraySegment <byte> buffer, WebSocketMessageType messageType, bool endOfMessage)
        {
            using (MemoryStream stream = _recycledStreamFactory())
            {
                WebSocketOpCode opCode = GetOppCode(messageType);

                if (_usePerMessageDeflate)
                {
                    // NOTE: Compression is currently work in progress and should NOT be used in this library.
                    // The code below is very inefficient for small messages. Ideally we would like to have some sort of moving window
                    // of data to get the best compression. And we don't want to create new buffers which is bad for GC.
                    using (MemoryStream temp = new MemoryStream())
                    {
                        DeflateStream deflateStream = new DeflateStream(temp, CompressionMode.Compress);
                        deflateStream.Write(buffer.Array, buffer.Offset, buffer.Count);
                        deflateStream.Flush();
                        var compressedBuffer = new ArraySegment <byte>(temp.ToArray());
                        WebSocketFrameWriter.Write(opCode, compressedBuffer, stream, endOfMessage, _isClient);
                        _logger(LogLevel.Debug, $"websocket.SendingFrame: {opCode}, {endOfMessage}, {compressedBuffer.Count}, compressed");
                    }
                }
                else
                {
                    WebSocketFrameWriter.Write(opCode, buffer, stream, endOfMessage, _isClient);
                    _logger(LogLevel.Debug, $"websocket.SendingFrame: {opCode}, {endOfMessage}, {buffer.Count}, uncompressed");
                }

                WriteStreamToNetwork(stream);
                _isContinuationFrame = !endOfMessage; // TODO: is this correct??
            }
        }
Beispiel #4
0
        /// Fire and forget close
        public void CloseOutput(WebSocketCloseStatus closeStatus, string statusDescription)
        {
            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);
                    WriteStreamToNetwork(stream);
                }
            }
        }
Beispiel #5
0
 /// Polite close (use the close handshake)
 public void Close(WebSocketCloseStatus closeStatus, string statusDescription)
 {
     if (_state == WebSocketState.Open)
     {
         using (MemoryStream stream = _recycledStreamFactory())
         {
             ArraySegment <byte> buffer = BuildClosePayload(closeStatus, statusDescription);
             WebSocketFrameWriter.Write(WebSocketOpCode.ConnectionClose, buffer, stream, true, _isClient);
             _logger(LogLevel.Debug, $"websocket.Close: {closeStatus}, {statusDescription}");
             WriteStreamToNetwork(stream);
             _state = WebSocketState.CloseSent;
         }
     }
     else
     {
         _logger(LogLevel.Warning, $"websocket already closed");
     }
 }
Beispiel #6
0
        /// Call this automatically from server side each keepAliveInterval period
        /// NOTE: ping payload must be 125 bytes or less
        public void SendPing()
        {
            _pingCounter++;
            _pingPayload = BitConverter.GetBytes(_pingCounter);

            var payload = new ArraySegment <byte>(_pingPayload);

            if (payload.Count > MAX_PING_PONG_PAYLOAD_LEN)
            {
                throw new InvalidOperationException($"Cannot send Ping: Max ping message size {MAX_PING_PONG_PAYLOAD_LEN} exceeded: {payload.Count}");
            }

            if (_state == WebSocketState.Open)
            {
                using (MemoryStream stream = _recycledStreamFactory())
                {
                    NeedsPing = false;
                    WebSocketFrameWriter.Write(WebSocketOpCode.Ping, payload, stream, true, _isClient);
                    _logger(LogLevel.Debug, $"websocket.Ping: {payload.Count}");
                    WriteStreamToNetwork(stream);
                }
            }
        }