protected void DoSendPongMessage()
        {
            WSFrame wsFrame = WSFrame.CreateFrame(WSFrameType.Pong, this.options.MaskingEnabled, "Hello");

            this.LogBufferContent("Sending pong frame: ", wsFrame.FrameData, 0, wsFrame.FrameData.Length);
            this.socketStream.Write(wsFrame.FrameData, 0, wsFrame.FrameData.Length);
        }
        protected void DoSendCloseFrame()
        {
            WSFrame wsFrame = WSFrame.CreateFrame(WSFrameType.Close, this.options.MaskingEnabled, ArrayUtil.Concat(this.closeStatus, this.closeReason));

            this.LogBufferContent("Sending close frame: ", wsFrame.FrameData, 0, wsFrame.FrameData.Length);
            this.socketStream.Write(wsFrame.FrameData, 0, wsFrame.FrameData.Length);
            this.subState = SubState.WaitForCloseResponse;
        }
        /// <summary>
        /// Removes the WSFrame at the top of the queue, and returns it.
        /// </summary>
        /// <returns>The WSFrame that is removed from the top of the queue.</returns>
        public WSFrame Dequeue()
        {
            WSFrame wsFrame = null;

            lock (this.queue.SyncRoot)
            {
                wsFrame = (WSFrame)this.queue.Dequeue();
            }
            return(wsFrame);
        }
 /// <summary>
 /// Adds a WSFrame to the bottom of the queue.
 /// </summary>
 /// <param name="wsFrame">The WSFrame to add to the queue.</param>
 /// <remarks>If Count == MaxCount, then the WSFrame at the top of the queue is removed and discarded before the new entry is added.</remarks>
 public void Enqueue(WSFrame wsFrame)
 {
     lock (this.queue.SyncRoot)
     {
         if (this.queue.Count == this.maxCount)
         {
             this.queue.Dequeue();
         }
         this.queue.Enqueue(wsFrame);
     }
 }
예제 #5
0
 public static void ApplyMask(WSFrame wsFrame)
 {
     if (wsFrame != null && wsFrame.payloadLength > 0)
     {
         int maskIndex = 0;
         for (int i = 0; i < wsFrame.payloadLength; i++)
         {
             maskIndex = wsFrame.maskIndex + (i % 4);
             wsFrame.frameData[wsFrame.payloadIndex + i] = (byte)(wsFrame.frameData[wsFrame.payloadIndex + i] ^ wsFrame.frameData[maskIndex]);
         }
     }
 }
        protected void EnqueueMessage(WSFrameType opCode, bool isMasked, byte[] payLoad, bool highPriority = false)
        {
            WSFrame wsFrame = WSFrame.CreateFrame(opCode, isMasked, payLoad);

            if (highPriority)
            {
                this.sendQueue.Poke(wsFrame);
            }
            else
            {
                this.sendQueue.Enqueue(wsFrame);
            }
        }
        protected bool DequeueAndSendMessages()
        {
            bool messagesSent = this.sendQueue.Count > 0;

            lock (this.sendLock)
            {
                while (this.sendQueue.Count > 0)
                {
                    WSFrame wsFrame = this.sendQueue.Dequeue();
                    this.LogBufferContent("Sending data frame: ", wsFrame.FrameData, 0, wsFrame.FrameData.Length);
                    this.socketStream.Write(wsFrame.FrameData, 0, wsFrame.FrameData.Length);
                }
            }
            return(messagesSent);
        }
 /// <summary>
 /// Inserts a WSFrame at the top of the queue.
 /// </summary>
 /// <param name="wsFrame">The WSFrame to add to the queue.</param>
 /// <remarks>May be used to insert high-priority messages at the top of the queue.</remarks>
 public void Poke(WSFrame wsFrame)
 {
     lock (this.queue.SyncRoot)
     {
         if (this.queue.Count > this.maxCount)
         {
             this.queue.Dequeue();
         }
         int count = this.queue.Count;
         this.queue.Enqueue(wsFrame);
         while (count > 0)
         {
             this.queue.Enqueue(this.queue.Dequeue());
         }
     }
 }
        protected void DoSendCloseResponse()
        {
            byte[] payLoad = null;
            if (this.lastRcvdFrame.OpCode == WSFrameType.Close && this.lastRcvdFrame.PayloadLength > 0)
            {
                // reply with the same status code and reason
                payLoad = this.lastRcvdFrame.PayloadBytes;
            }

            WSFrame wsFrame = WSFrame.CreateFrame(WSFrameType.Close, this.options.MaskingEnabled, payLoad);

            this.LogBufferContent("Sending close frame: ", wsFrame.FrameData, 0, wsFrame.FrameData.Length);
            this.socketStream.Write(wsFrame.FrameData, 0, wsFrame.FrameData.Length);
            this.socketStream.Flush();

            this.subState = SubState.CloseTcpConnection;
        }
        protected void DoWaitCloseResponse()
        {
            int bytesRead = 0;

            this.posHeaderEOF  = 0;
            this.bytesInBuffer = 0;

            if (this.socket.Poll(this.waitCloseMsgTimeout, SelectMode.SelectRead) == true && this.socket.Available > 0)
            {
                do
                {
                    bytesRead = this.socketStream.Read(this.receiveBuffer, this.bytesInBuffer, this.receiveBuffer.Length - this.bytesInBuffer);
                    if (bytesRead > 0)
                    {
                        this.bytesInBuffer += bytesRead;
                        if (WSFrame.TryParse(this.receiveBuffer, 0, this.bytesInBuffer, this.options.MaxReceiveFrameLength, out this.lastRcvdFrame) == true)
                        {
                            // remove data-frame from buffer
                            Array.Copy(this.receiveBuffer, this.lastRcvdFrame.FrameData.Length, this.receiveBuffer, 0, this.bytesInBuffer - this.lastRcvdFrame.FrameData.Length);
                            this.bytesInBuffer = this.bytesInBuffer - this.lastRcvdFrame.FrameData.Length;

                            // check for close frame
                            if (this.lastRcvdFrame.OpCode == WSFrameType.Close)
                            {
                                this.LogBufferContent("Close frame received: ", this.lastRcvdFrame.FrameData, 0, this.lastRcvdFrame.FrameData.Length);
                                this.subState = SubState.CloseTcpConnection;
                                return;
                            }

                            this.LogBufferContent("Data frame received: ", this.lastRcvdFrame.FrameData, 0, this.lastRcvdFrame.FrameData.Length);
                        }
                    }
                }while (this.socket.Available > 0 && this.bytesInBuffer < this.receiveBuffer.Length);
            }

            Logger.WriteError(this.loggerID, "Close frame not received.");
            this.subState = SubState.Failed;
        }
예제 #11
0
        /// <summary>
        /// Parses a byte-array at startPos to its equivalent RFC 6455 BFP frame. The return value indicates whether the operation succeeded.
        /// </summary>
        /// <param name="dataBuffer">A source byte-array containing the bytes to convert.</param>
        /// <param name="startPos">Start position in the source byte-array.</param>
        /// <param name="length">Number of bytes to parse.</param>
        /// <param name="maxFrameLength">Maximum frame size allowed.</param>
        /// <param name="dataFrame">The resulting BFP frame or null.</param>
        /// <returns>true if the source byte-array was converted successfully; otherwise, false</returns>
        public static bool TryParse(byte[] dataBuffer, int startPos, int length, int maxFrameLength, out WSFrame dataFrame)
        {
            dataFrame = null;

            if (dataBuffer == null || dataBuffer.Length == 0 || dataBuffer.Length < (startPos + length))
            {
                return(false);
            }

            byte controlByte0 = dataBuffer[startPos];
            byte controlByte1 = dataBuffer[startPos + 1];
            byte length8      = (byte)(controlByte1 & 0x7F);
            bool isMasked     = ((controlByte1 & 0x80) == 0x80);
            int  maskIndex    = 0;

            byte[] mask = new byte[4];

            // get payload index and length
            Int32  payloadIndex    = 0;
            UInt64 payloadLength64 = 0;

            if (length8 == 127)
            {
                maskIndex       = (isMasked ? 10 : 0);
                payloadIndex    = (isMasked ? 14 : 10);
                payloadLength64 = dataBuffer.ToUInt64(startPos + 2);
            }
            else if (length8 == 126)
            {
                maskIndex       = (isMasked ? 4 : 0);
                payloadIndex    = (isMasked ? 8 : 4);
                payloadLength64 = dataBuffer.ToUInt16(startPos + 2);
            }
            else             // must be <= 125
            {
                maskIndex       = (isMasked ? 2 : 0);
                payloadIndex    = (isMasked ? 6 : 2);
                payloadLength64 = length8;
            }

            // calculate frame length
            Int32 frameLength = payloadIndex + (Int32)payloadLength64;

            // check for max allowed length
            if (frameLength > maxFrameLength)
            {
                throw new NotSupportedException(string.Concat("Maximum frame size of ", maxFrameLength, " bytes has been exceeded."));
            }

            // create WSFrame if full frame has been received
            if (frameLength <= length)
            {
                dataFrame = new WSFrame()
                {
                    maskIndex     = maskIndex,
                    payloadIndex  = payloadIndex,
                    payloadLength = (Int32)payloadLength64,
                    frameData     = new byte[frameLength]
                };

                Array.Copy(dataBuffer, startPos, dataFrame.frameData, 0, frameLength);

                if (isMasked)
                {
                    ApplyMask(dataFrame);
                }

                return(true);
            }

            return(false);
        }
예제 #12
0
        /// <summary>
        /// Creates an RFC 6455 BFP frame with the opcode and payload bytes specified.
        /// </summary>
        /// <param name="opCode">BFP opcode.</param>
        /// <param name="isMasked">Boolean indicating whether to mask the payload.</param>
        /// <param name="payLoad">Payload bytes.</param>
        /// <returns></returns>
        public static WSFrame CreateFrame(WSFrameType opCode, bool isMasked, byte[] payLoad)
        {
            // TODO - add code to support continuation frames
            // - add long maxFrameLength parameter
            // - return array of WSFrame objects

            byte controlByte0 = (byte)(0x80 | (byte)opCode);
            byte controlByte1 = (isMasked && payLoad != null && payLoad.Length > 0 ? (byte)0x80 : (byte)0x00);

            byte[] mask         = (isMasked ? CryptoUtils.GetRandomBytes(4) : new byte[0]);
            int    maskIndex    = 0;
            Int32  payloadIndex = 0;
            UInt16 length16     = 0;
            UInt32 length32     = 0;
            UInt64 length64     = 0;

            byte[] frameData = null;

            if (payLoad == null || payLoad.Length == 0)
            {
                length32     = 0;
                payloadIndex = 0;
                frameData    = ArrayUtil.Concat(controlByte0, controlByte1);
            }
            else if (payLoad.Length <= 125)
            {
                controlByte1 = (byte)(controlByte1 | (byte)payLoad.Length);
                length32     = (UInt32)payLoad.Length;
                maskIndex    = (isMasked ? 2 : 0);
                payloadIndex = (isMasked ? 6 : 2);
                frameData    = ArrayUtil.Concat(controlByte0, controlByte1, mask, payLoad);
            }
            else if (payLoad.Length <= UInt16.MaxValue)
            {
                controlByte1 = (byte)(controlByte1 | (byte)126);
                length16     = (UInt16)payLoad.Length;
                length32     = length16;
                maskIndex    = (isMasked ? 4 : 0);
                payloadIndex = (isMasked ? 8 : 4);
                frameData    = ArrayUtil.Concat(controlByte0, controlByte1, length16, mask, payLoad);
            }
            else
            {
                controlByte1 = (byte)(controlByte1 | (byte)127);
                length32     = (UInt32)payLoad.Length;
                length64     = (UInt64)payLoad.Length;
                maskIndex    = (isMasked ? 10 : 0);
                payloadIndex = (isMasked ? 14 : 10);
                frameData    = ArrayUtil.Concat(controlByte0, controlByte1, length64, mask, payLoad);
            }

            WSFrame dataFrame = new WSFrame()
            {
                maskIndex     = maskIndex,
                payloadIndex  = payloadIndex,
                payloadLength = (Int32)length32,
                frameData     = frameData
            };

            if (isMasked)
            {
                //	Logger.WriteDebug("wsframe", string.Concat("raw: ", frameData.ToHex()));
                ApplyMask(dataFrame);
            }

            return(dataFrame);
        }
        protected void DoReceiving()
        {
            // process data in buffer
            if (this.bytesInBuffer > 0)
            {
                if (WSFrame.TryParse(this.receiveBuffer, 0, this.bytesInBuffer, this.options.MaxReceiveFrameLength, out this.lastRcvdFrame) == true)
                {
                    // restart activity timer
                    if (this.activityTimerEnabled)
                    {
                        this.activityTimer.Restart(ActivityTimerState.WaitingForMessage);
                    }

                    // remove data-frame from buffer
                    Array.Copy(this.receiveBuffer, this.lastRcvdFrame.FrameData.Length, this.receiveBuffer, 0, this.bytesInBuffer - this.lastRcvdFrame.FrameData.Length);
                    this.bytesInBuffer = this.bytesInBuffer - this.lastRcvdFrame.FrameData.Length;

                    // take action based on opcode
                    switch (this.lastRcvdFrame.OpCode)
                    {
                    case WSFrameType.Continuation:
                        // TODO - implement continuation frames
                        break;

                    case WSFrameType.Text:
                        this.LogBufferContent("Text frame received: ", this.lastRcvdFrame.FrameData, 0, this.lastRcvdFrame.FrameData.Length);
                        this.OnTextReceived(this.lastRcvdFrame.PayloadText);
                        break;

                    case WSFrameType.Binary:
                        this.LogBufferContent("Data frame received: ", this.lastRcvdFrame.FrameData, 0, this.lastRcvdFrame.FrameData.Length);
                        this.OnDataReceived(this.lastRcvdFrame.PayloadBytes);
                        break;

                    case WSFrameType.Close:
                        this.LogBufferContent("Close frame received: ", this.lastRcvdFrame.FrameData, 0, this.lastRcvdFrame.FrameData.Length);
                        // based on RFC6455 we must stop sending and receiving messages after Close response is sent
                        this.activityTimer.Stop();
                        this.state    = WebSocketState.Disconnecting;
                        this.subState = SubState.SendCloseResponse;
                        return;

                    case WSFrameType.Ping:
                        this.LogBufferContent("Ping frame received: ", this.lastRcvdFrame.FrameData, 0, this.lastRcvdFrame.FrameData.Length);
                        this.DoSendPongMessage();
                        break;

                    case WSFrameType.Pong:
                        this.LogBufferContent("Pong frame received: ", this.lastRcvdFrame.FrameData, 0, this.lastRcvdFrame.FrameData.Length);
                        // no need to do anything
                        break;

                    default:
                        this.LogBufferContent("Unknown frame received: ", this.lastRcvdFrame.FrameData, 0, this.lastRcvdFrame.FrameData.Length);
                        break;
                    }
                }
            }

            // send queued messages
            if (this.DequeueAndSendMessages() && this.activityTimerEnabled)
            {
                this.activityTimer.Restart(ActivityTimerState.MessageSent);
            }

            // get more data
            if (this.socket.Poll(this.waitReceiveTimeout, SelectMode.SelectRead) == true && this.socket.Available > 0)
            {
                int bytesRead = this.socketStream.Read(this.receiveBuffer, this.bytesInBuffer, this.receiveBuffer.Length - this.bytesInBuffer);
                this.bytesInBuffer += bytesRead;
                if (bytesRead > 0)
                {
                    this.activityTimer.Restart(ActivityTimerState.WaitingForMessage);
                }
            }

            // check activity timer
            if (this.activityTimerEnabled && this.activityTimer.HasTimedOut)
            {
                switch ((ActivityTimerState)this.activityTimer.State)
                {
                case ActivityTimerState.MessageSent:
                case ActivityTimerState.WaitingForMessage:
                    this.DoSendPingMessage();
                    activityTimer.Restart(ActivityTimerState.WaitingForPingResponse);
                    break;

                case ActivityTimerState.WaitingForPingResponse:
                    Logger.WriteError(this.loggerID, string.Concat("Ping response timed out."));
                    activityTimer.Stop();
                    this.subState = SubState.Failed;
                    break;
                }
            }
        }