public void SendData(byte[] data)
        {
            if (_initialMsgTimeout > 0)
            {
                _receiveDone.Set();
                _initialMsgTimeout = 0;
            }
            WebSocketFrame dataMessageFrame = new WebSocketFrame()
            {
                Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = data
            };

            dataMessageFrame.Header.IsEnd  = true;
            dataMessageFrame.Header.Opcode = WebSocketReader.OpCode.Binary;
            SendSocket(dataMessageFrame.ToBytes());
        }
        /// <summary>
        /// Informs the otherside that we accepted their upgrade request
        /// </summary>
        /// <param name="pHandshakeResponse">The HTTP 1.1 101 response that says Yay \o/ </param>
        private void SendUpgradeSuccess(string pHandshakeResponse)
        {
            // Create a new websocket state so we can keep track of data in between network reads.
            WebSocketState socketState = new WebSocketState()
            {
                ReceivedBytes = new List <byte>(), Header = WebsocketFrameHeader.HeaderDefault(), FrameComplete = true
            };

            byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(pHandshakeResponse);



            try
            {
                if (_initialMsgTimeout > 0)
                {
                    _receiveDone.Reset();
                }
                // Begin reading the TCP stream before writing the Upgrade success message to the other side of the stream.
                _networkContext.Stream.BeginRead(_buffer, 0, _bufferLength, OnReceive, socketState);

                // Write the upgrade handshake success message
                _networkContext.Stream.Write(bhandshakeResponse, 0, bhandshakeResponse.Length);
                _networkContext.Stream.Flush();
                _upgraded = true;
                UpgradeCompletedDelegate d = OnUpgradeCompleted;
                if (d != null)
                {
                    d(this, new UpgradeCompletedEventArgs());
                }
                if (_initialMsgTimeout > 0)
                {
                    if (!_receiveDone.WaitOne(TimeSpan.FromMilliseconds(_initialMsgTimeout)))
                    {
                        Close(string.Empty);
                    }
                }
            }
            catch (IOException)
            {
                Close(string.Empty);
            }
            catch (ObjectDisposedException)
            {
                Close(string.Empty);
            }
        }
        /// <summary>
        /// Sends a Ping check to the other side.  The other side SHOULD respond as soon as possible with a pong frame.   This interleaves with incoming fragmented frames.
        /// </summary>
        public void SendPingCheck()
        {
            if (_initialMsgTimeout > 0)
            {
                _receiveDone.Set();
                _initialMsgTimeout = 0;
            }
            WebSocketFrame pingFrame = new WebSocketFrame()
            {
                Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = new byte[0]
            };

            pingFrame.Header.Opcode = WebSocketReader.OpCode.Ping;
            pingFrame.Header.IsEnd  = true;
            _pingtime = System.Environment.TickCount;
            SendSocket(pingFrame.ToBytes());
        }
        /// <summary>
        /// Sends a string to the other side
        /// </summary>
        /// <param name="message">the string message that is to be sent</param>
        public void SendMessage(string message)
        {
            if (_initialMsgTimeout > 0)
            {
                _receiveDone.Set();
                _initialMsgTimeout = 0;
            }
            byte[]         messagedata      = Encoding.UTF8.GetBytes(message);
            WebSocketFrame textMessageFrame = new WebSocketFrame()
            {
                Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = messagedata
            };

            textMessageFrame.Header.Opcode = WebSocketReader.OpCode.Text;
            textMessageFrame.Header.IsEnd  = true;
            SendSocket(textMessageFrame.ToBytes());
        }
        /// <summary>
        /// Closes the websocket connection.   Sends a close message to the other side if it hasn't already done so.
        /// </summary>
        /// <param name="message"></param>
        public void Close(string message)
        {
            if (_initialMsgTimeout > 0)
            {
                _receiveDone.Set();
                _initialMsgTimeout = 0;
            }
            if (_networkContext == null)
            {
                return;
            }
            if (_networkContext.Stream != null)
            {
                if (_networkContext.Stream.CanWrite)
                {
                    byte[]         messagedata        = Encoding.UTF8.GetBytes(message);
                    WebSocketFrame closeResponseFrame = new WebSocketFrame()
                    {
                        Header           = WebsocketFrameHeader.HeaderDefault(),
                        WebSocketPayload = messagedata
                    };
                    closeResponseFrame.Header.Opcode     = WebSocketReader.OpCode.Close;
                    closeResponseFrame.Header.PayloadLen = (ulong)messagedata.Length;
                    closeResponseFrame.Header.IsEnd      = true;
                    SendSocket(closeResponseFrame.ToBytes());
                }
            }
            CloseDelegate closeD = OnClose;

            if (closeD != null)
            {
                closeD(this, new CloseEventArgs());
            }

            _closing = true;
        }
        /// <summary>
        /// Attempts to read a header off the provided buffer.  Returns true, exports a WebSocketFrameheader,
        /// and an int to move the buffer forward when it reads a header.  False when it can't read a header
        /// </summary>
        /// <param name="pBuffer">Bytes read from the stream</param>
        /// <param name="pOffset">Starting place in the stream to begin trying to read from</param>
        /// <param name="length">Lenth in the stream to try and read from.  Provided for cases where the
        /// buffer's length is larger then the data in it</param>
        /// <param name="oHeader">Outputs the read WebSocket frame header</param>
        /// <param name="moveBuffer">Informs the calling stream to move the buffer forward</param>
        /// <returns>True if it got a header, False if it didn't get a header</returns>
        public static bool TryReadHeader(byte[] pBuffer, int pOffset, int length, out WebsocketFrameHeader oHeader,
                                         out int moveBuffer)
        {
            oHeader = WebsocketFrameHeader.ZeroHeader;
            int minumheadersize = 2;

            if (length > pBuffer.Length - pOffset)
            {
                throw new ArgumentOutOfRangeException("The Length specified was larger the byte array supplied");
            }
            if (length < minumheadersize)
            {
                moveBuffer = 0;
                return(false);
            }

            byte nibble1 = (byte)(pBuffer[pOffset] & 0xF0); //FIN/RSV1/RSV2/RSV3
            byte nibble2 = (byte)(pBuffer[pOffset] & 0x0F); // Opcode block

            oHeader = new WebsocketFrameHeader();
            oHeader.SetDefault();

            if ((nibble1 & WebSocketReader.EndBit) == WebSocketReader.EndBit)
            {
                oHeader.IsEnd = true;
            }
            else
            {
                oHeader.IsEnd = false;
            }
            //Opcode
            oHeader.Opcode = (WebSocketReader.OpCode)nibble2;
            //Mask
            oHeader.IsMasked = Convert.ToBoolean((pBuffer[pOffset + 1] & 0x80) >> 7);

            // Payload length
            oHeader.PayloadLen = (byte)(pBuffer[pOffset + 1] & 0x7F);

            int index = 2; // LargerPayload length starts at byte 3

            switch (oHeader.PayloadLen)
            {
            case 126:
                minumheadersize += 2;
                if (length < minumheadersize)
                {
                    moveBuffer = 0;
                    return(false);
                }
                Array.Reverse(pBuffer, pOffset + index, 2);      // two bytes
                oHeader.PayloadLen = BitConverter.ToUInt16(pBuffer, pOffset + index);
                index += 2;
                break;

            case 127:       // we got more this is a bigger frame
                // 8 bytes - uint64 - most significant bit 0  network byte order
                minumheadersize += 8;
                if (length < minumheadersize)
                {
                    moveBuffer = 0;
                    return(false);
                }
                Array.Reverse(pBuffer, pOffset + index, 8);
                oHeader.PayloadLen = BitConverter.ToUInt64(pBuffer, pOffset + index);
                index += 8;
                break;
            }
            //oHeader.PayloadLeft = oHeader.PayloadLen; // Start the count in case it's chunked over the network.  This is different then frame fragmentation
            if (oHeader.IsMasked)
            {
                minumheadersize += 4;
                if (length < minumheadersize)
                {
                    moveBuffer = 0;
                    return(false);
                }
                oHeader.Mask = BitConverter.ToInt32(pBuffer, pOffset + index);
                index       += 4;
            }
            moveBuffer = index;
            return(true);
        }
        /// <summary>
        /// Processes a websocket frame and triggers consumer events
        /// </summary>
        /// <param name="psocketState">We need to modify the websocket state here depending on the frame</param>
        private void ProcessFrame(WebSocketState psocketState)
        {
            if (psocketState.Header.IsMasked)
            {
                byte[] unmask = psocketState.ReceivedBytes.ToArray();
                WebSocketReader.Mask(psocketState.Header.Mask, unmask);
                psocketState.ReceivedBytes = new List <byte>(unmask);
            }
            if (psocketState.Header.Opcode != WebSocketReader.OpCode.Continue && _initialMsgTimeout > 0)
            {
                _receiveDone.Set();
                _initialMsgTimeout = 0;
            }
            switch (psocketState.Header.Opcode)
            {
            case WebSocketReader.OpCode.Ping:
                PingDelegate pingD = OnPing;
                if (pingD != null)
                {
                    pingD(this, new PingEventArgs());
                }

                WebSocketFrame pongFrame = new WebSocketFrame()
                {
                    Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = new byte[0]
                };
                pongFrame.Header.Opcode = WebSocketReader.OpCode.Pong;
                pongFrame.Header.IsEnd  = true;
                SendSocket(pongFrame.ToBytes());
                break;

            case WebSocketReader.OpCode.Pong:

                PongDelegate pongD = OnPong;
                if (pongD != null)
                {
                    pongD(this, new PongEventArgs()
                    {
                        PingResponseMS = System.Environment.TickCount - _pingtime
                    });
                }
                break;

            case WebSocketReader.OpCode.Binary:
                if (!psocketState.Header.IsEnd)     // Not done, so we need to store this and wait for the end frame.
                {
                    psocketState.ContinuationFrame = new WebSocketFrame
                    {
                        Header           = psocketState.Header,
                        WebSocketPayload =
                            psocketState.ReceivedBytes.ToArray()
                    };
                }
                else
                {
                    // Send Done Event!
                    DataDelegate dataD = OnData;
                    if (dataD != null)
                    {
                        dataD(this, new WebsocketDataEventArgs()
                        {
                            Data = psocketState.ReceivedBytes.ToArray()
                        });
                    }
                }
                break;

            case WebSocketReader.OpCode.Text:
                if (!psocketState.Header.IsEnd)     // Not done, so we need to store this and wait for the end frame.
                {
                    psocketState.ContinuationFrame = new WebSocketFrame
                    {
                        Header           = psocketState.Header,
                        WebSocketPayload =
                            psocketState.ReceivedBytes.ToArray()
                    };
                }
                else
                {
                    TextDelegate textD = OnText;
                    if (textD != null)
                    {
                        textD(this, new WebsocketTextEventArgs()
                        {
                            Data = Encoding.UTF8.GetString(psocketState.ReceivedBytes.ToArray())
                        });
                    }

                    // Send Done Event!
                }
                break;

            case WebSocketReader.OpCode.Continue:      // Continuation.  Multiple frames worth of data for one message.   Only valid when not using Control Opcodes
                //Console.WriteLine("currhead " + psocketState.Header.IsEnd);
                //Console.WriteLine("Continuation! " + psocketState.ContinuationFrame.Header.IsEnd);

                if (psocketState.ContinuationFrame == null && psocketState.Header.IsEnd)
                {
                    // This must be the first and last frame.   Why didn't we just send a BinaryData?
                    DataDelegate dataD = OnData;
                    if (dataD != null)
                    {
                        dataD(this, new WebsocketDataEventArgs()
                        {
                            Data = psocketState.ReceivedBytes.ToArray()
                        });
                    }
                    break;
                }

                byte[] combineddata = new byte[psocketState.ReceivedBytes.Count + psocketState.ContinuationFrame.WebSocketPayload.Length];
                byte[] newdata      = psocketState.ReceivedBytes.ToArray();
                Buffer.BlockCopy(psocketState.ContinuationFrame.WebSocketPayload, 0, combineddata, 0, psocketState.ContinuationFrame.WebSocketPayload.Length);
                Buffer.BlockCopy(newdata, 0, combineddata,
                                 psocketState.ContinuationFrame.WebSocketPayload.Length, newdata.Length);
                psocketState.ContinuationFrame.WebSocketPayload = combineddata;
                psocketState.Header.PayloadLen = (ulong)combineddata.Length;
                if (psocketState.Header.IsEnd)
                {
                    if (psocketState.ContinuationFrame.Header.Opcode == WebSocketReader.OpCode.Text)
                    {
                        // Send Done event
                        TextDelegate textD = OnText;
                        if (textD != null)
                        {
                            textD(this, new WebsocketTextEventArgs()
                            {
                                Data = Encoding.UTF8.GetString(combineddata)
                            });
                        }
                    }
                    else if (psocketState.ContinuationFrame.Header.Opcode == WebSocketReader.OpCode.Binary)
                    {
                        // Send Done event
                        DataDelegate dataD = OnData;
                        if (dataD != null)
                        {
                            dataD(this, new WebsocketDataEventArgs()
                            {
                                Data = combineddata
                            });
                        }
                    }
                    else
                    {
                        // protocol violation
                    }
                    psocketState.ContinuationFrame = null;
                }
                break;

            case WebSocketReader.OpCode.Close:
                Close(string.Empty);

                break;
            }
            psocketState.Header.SetDefault();
            psocketState.ReceivedBytes.Clear();
            psocketState.ExpectedBytes = 0;
        }
        /// <summary>
        /// This is our ugly Async OnReceive event handler.
        /// This chunks the input stream based on the length of the provided buffer and processes out
        /// as many frames as it can.   It then moves the unprocessed data to the beginning of the buffer.
        /// </summary>
        /// <param name="ar">Our Async State from beginread</param>
        private void OnReceive(IAsyncResult ar)
        {
            WebSocketState _socketState = ar.AsyncState as WebSocketState;

            try
            {
                int bytesRead = _networkContext.Stream.EndRead(ar);
                if (bytesRead == 0)
                {
                    // Do Disconnect
                    _networkContext.Stream.Dispose();
                    _networkContext = null;
                    return;
                }
                _bufferPosition += bytesRead;

                if (_bufferPosition > _bufferLength)
                {
                    // Message too big for chunksize..   not sure how this happened...
                    //Close(string.Empty);
                }

                int  offset                = 0;
                bool headerread            = true;
                int  headerforwardposition = 0;
                while (headerread && offset < bytesRead)
                {
                    if (_socketState.FrameComplete)
                    {
                        WebsocketFrameHeader pheader = WebsocketFrameHeader.ZeroHeader;

                        headerread = WebSocketReader.TryReadHeader(_buffer, offset, _bufferPosition - offset, out pheader,
                                                                   out headerforwardposition);
                        offset += headerforwardposition;

                        if (headerread)
                        {
                            _socketState.FrameComplete = false;
                            if (pheader.PayloadLen > (ulong)_maxPayloadBytes)
                            {
                                Close("Invalid Payload size");

                                return;
                            }
                            if (pheader.PayloadLen > 0)
                            {
                                if ((int)pheader.PayloadLen > _bufferPosition - offset)
                                {
                                    byte[] writebytes = new byte[_bufferPosition - offset];

                                    Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int)_bufferPosition - offset);
                                    _socketState.ExpectedBytes = (int)pheader.PayloadLen;
                                    _socketState.ReceivedBytes.AddRange(writebytes);
                                    _socketState.Header = pheader; // We need to add the header so that we can unmask it
                                    offset += (int)_bufferPosition - offset;
                                }
                                else
                                {
                                    byte[] writebytes = new byte[pheader.PayloadLen];
                                    Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int)pheader.PayloadLen);
                                    WebSocketReader.Mask(pheader.Mask, writebytes);
                                    pheader.IsMasked           = false;
                                    _socketState.FrameComplete = true;
                                    _socketState.ReceivedBytes.AddRange(writebytes);
                                    _socketState.Header = pheader;
                                    offset += (int)pheader.PayloadLen;
                                }
                            }
                            else
                            {
                                pheader.Mask = 0;
                                _socketState.FrameComplete = true;
                                _socketState.Header        = pheader;
                            }

                            if (_socketState.FrameComplete)
                            {
                                ProcessFrame(_socketState);
                                _socketState.Header.SetDefault();
                                _socketState.ReceivedBytes.Clear();
                                _socketState.ExpectedBytes = 0;
                            }
                        }
                    }
                    else
                    {
                        WebsocketFrameHeader frameHeader = _socketState.Header;
                        int bytesleft = _socketState.ExpectedBytes - _socketState.ReceivedBytes.Count;

                        if (bytesleft > _bufferPosition)
                        {
                            byte[] writebytes = new byte[_bufferPosition];

                            Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int)_bufferPosition);
                            _socketState.ReceivedBytes.AddRange(writebytes);
                            _socketState.Header = frameHeader; // We need to add the header so that we can unmask it
                            offset += (int)_bufferPosition;
                        }
                        else
                        {
                            byte[] writebytes = new byte[_bufferPosition];
                            Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int)_bufferPosition);
                            _socketState.FrameComplete = true;
                            _socketState.ReceivedBytes.AddRange(writebytes);
                            _socketState.Header = frameHeader;
                            offset += (int)_bufferPosition;
                        }
                        if (_socketState.FrameComplete)
                        {
                            ProcessFrame(_socketState);
                            _socketState.Header.SetDefault();
                            _socketState.ReceivedBytes.Clear();
                            _socketState.ExpectedBytes = 0;
                            // do some processing
                        }
                    }
                }
                if (offset > 0)
                {
                    // If the buffer is maxed out..  we can just move the cursor.   Nothing to move to the beginning.
                    if (offset < _buffer.Length)
                    {
                        Buffer.BlockCopy(_buffer, offset, _buffer, 0, _bufferPosition - offset);
                    }
                    _bufferPosition -= offset;
                }
                if (_networkContext.Stream != null && _networkContext.Stream.CanRead && !_closing)
                {
                    _networkContext.Stream.BeginRead(_buffer, _bufferPosition, _bufferLength - _bufferPosition, OnReceive,
                                                     _socketState);
                }
                else
                {
                    // We can't read the stream anymore...
                }
            }
            catch (IOException)
            {
                Close("Undefined Error");
            }
            catch (ObjectDisposedException)
            {
                try
                {
                    Close("Undefined Error");
                }
                catch (Exception)
                {
                    // we don't care
                }
            }
            catch (NullReferenceException)
            {
                // The socket was probably disposed
            }
        }