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;
        }
        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;
                }
            }
        }