context: using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.IO;
  using System.Net;
  using System.Text;
  using System.Threading;
  using System.Threading.Tasks;
  using MediaBrowser.Model.Cryptography;
  using MediaBrowser.Model.IO;
  using SocketHttpListener.Net.WebSockets;
  using SocketHttpListener.Primitives;
  using HttpStatusCode = SocketHttpListener.Net.HttpStatusCode;
  using System.Net.Sockets;
  using WebSocketState = System.Net.WebSockets.WebSocketState;
  
  namespace SocketHttpListener
  {
      /// <summary>
      /// Implements the WebSocket interface.
      /// </summary>
      /// <remarks>
      /// The WebSocket class provides a set of methods and properties for two-way communication using
      /// the WebSocket protocol (<see href="http://tools.ietf.org/html/rfc6455">RFC 6455</see>).
      /// </remarks>
      public class WebSocket : IDisposable
      {
          #region Private Fields
  
          private string _base64Key;
          private Action _closeContext;
          private CompressionMethod _compression;
          private WebSocketContext _context;
          private CookieCollection _cookies;
          private AutoResetEvent _exitReceiving;
          private object _forConn;
          private object _forEvent;
          private object _forMessageEventQueue;
          private object _forSend;
          private const string _guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
          private Func<WebSocketContext, string>
                                          _handshakeRequestChecker;
          private Queue<MessageEventArgs> _messageEventQueue;
          private uint _nonceCount;
          private string _origin;
          private bool _preAuth;
          private string _protocol;
          private string[] _protocols;
          private Uri _proxyUri;
          private volatile WebSocketState _readyState;
          private AutoResetEvent _receivePong;
          private bool _secure;
          private Stream _stream;
          private Uri _uri;
          private const string _version = "13";
  
          #endregion
  
          #region Internal Fields
  
          internal const int FragmentLength = 1016; // Max value is int.MaxValue - 14.
  
          #endregion
  
          #region Internal Constructors
  
          // As server
          internal WebSocket(string protocol)
          {
              _protocol = protocol;
          }
  
          public void SetContext(HttpListenerWebSocketContext context, Action closeContextFn, Stream stream)
          {
              _context = context;
  
              _closeContext = closeContextFn;
              _secure = context.IsSecureConnection;
              _stream = stream;
  
              init();
          }
  
          public static TimeSpan DefaultKeepAliveInterval
          {
              // In the .NET Framework, this pulls the value from a P/Invoke.  Here we just hardcode it to a reasonable default.
              get { return TimeSpan.FromSeconds(30); }
          }
  
          #endregion
  
          /// <summary>
          /// Gets the state of the WebSocket connection.
          /// </summary>
          /// <value>
          /// One of the <see cref="WebSocketState"/> enum values, indicates the state of the WebSocket
          /// connection. The default value is <see cref="WebSocketState.Connecting"/>.
          /// </value>
          public WebSocketState ReadyState
          {
              get
              {
                  return _readyState;
              }
          }
  
          #region Public Events
  
          /// <summary>
          /// Occurs when the WebSocket connection has been closed.
          /// </summary>
          public event EventHandler<CloseEventArgs> OnClose;
  
          /// <summary>
          /// Occurs when the <see cref="WebSocket"/> gets an error.
          /// </summary>
          public event EventHandler<ErrorEventArgs> OnError;
  
          /// <summary>
          /// Occurs when the <see cref="WebSocket"/> receives a message.
          /// </summary>
          public event EventHandler<MessageEventArgs> OnMessage;
  
          /// <summary>
          /// Occurs when the WebSocket connection has been established.
          /// </summary>
          public event EventHandler OnOpen;
  
          #endregion
  
          #region Private Methods
  
          private void close(CloseStatusCode code, string reason, bool wait)
          {
              close(new PayloadData(((ushort)code).Append(reason)), !code.IsReserved(), wait);
          }
  
          private void close(PayloadData payload, bool send, bool wait)
          {
              lock (_forConn)
              {
                  if (_readyState == WebSocketState.CloseSent || _readyState == WebSocketState.Closed)
                  {
                      return;
                  }
  
                  _readyState = WebSocketState.CloseSent;
              }
  
              var e = new CloseEventArgs(payload);
              e.WasClean =
                closeHandshake(
                    send ? WebSocketFrame.CreateCloseFrame(Mask.Unmask, payload).ToByteArray() : null,
                    wait ? 1000 : 0);
  
              _readyState = WebSocketState.Closed;
              try
              {
                  OnClose.Emit(this, e);
              }
              catch (Exception ex)
              {
                  error("An exception has occurred while OnClose.", ex);
              }
          }
  
          private bool closeHandshake(byte[] frameAsBytes, int millisecondsTimeout)
          {
              var sent = frameAsBytes != null && writeBytes(frameAsBytes);
              var received =
                millisecondsTimeout == 0 ||
                (sent && _exitReceiving != null && _exitReceiving.WaitOne(millisecondsTimeout));
  
              closeServerResources();
  
              if (_receivePong != null)
              {
                  _receivePong.Dispose();
                  _receivePong = null;
              }
  
              if (_exitReceiving != null)
              {
                  _exitReceiving.Dispose();
                  _exitReceiving = null;
              }
  
              var result = sent && received;
  
              return result;
          }
  
          // As server
          private void closeServerResources()
          {
              if (_closeContext == null)
                  return;
  
              try
              {
                  _closeContext();
              }
              catch (SocketException)
              {
                  // it could be unable to send the handshake response
              }
  
              _closeContext = null;
              _stream = null;
              _context = null;
          }
  
          private bool concatenateFragmentsInto(Stream dest)
          {
              while (true)
              {
                  var frame = WebSocketFrame.Read(_stream, true);
                  if (frame.IsFinal)
                  {
                      /* FINAL */
  
                      // CONT
                      if (frame.IsContinuation)
                      {
                          dest.WriteBytes(frame.PayloadData.ApplicationData);
                          break;
                      }
  
                      // PING
                      if (frame.IsPing)
                      {
                          processPingFrame(frame);
                          continue;
                      }
  
                      // PONG
                      if (frame.IsPong)
                      {
                          processPongFrame(frame);
                          continue;
                      }
  
                      // CLOSE
                      if (frame.IsClose)
                          return processCloseFrame(frame);
                  }
                  else
                  {
                      /* MORE */
  
                      // CONT
                      if (frame.IsContinuation)
                      {
                          dest.WriteBytes(frame.PayloadData.ApplicationData);
                          continue;
                      }
                  }
  
                  // ?
                  return processUnsupportedFrame(
                    frame,
                    CloseStatusCode.IncorrectData,
                    "An incorrect data has been received while receiving fragmented data.");
              }
  
              return true;
          }
  
          // As server
          private HttpResponse createHandshakeCloseResponse(HttpStatusCode code)
          {
              var res = HttpResponse.CreateCloseResponse(code);
              res.Headers["Sec-WebSocket-Version"] = _version;
  
              return res;
          }
  
          private MessageEventArgs dequeueFromMessageEventQueue()
          {
              lock (_forMessageEventQueue)
                  return _messageEventQueue.Count > 0
                         ? _messageEventQueue.Dequeue()
                         : null;
          }
  
          private void enqueueToMessageEventQueue(MessageEventArgs e)
          {
              lock (_forMessageEventQueue)
                  _messageEventQueue.Enqueue(e);
          }
  
          private void error(string message, Exception exception)
          {
              try
              {
                  if (exception != null)
                  {
                      message += ". Exception.Message: " + exception.Message;
                  }
                  OnError.Emit(this, new ErrorEventArgs(message));
              }
              catch (Exception ex)
              {
              }
          }
  
          private void error(string message)
          {
              try
              {
                  OnError.Emit(this, new ErrorEventArgs(message));
              }
              catch (Exception ex)
              {
              }
          }
  
          private void init()
          {
              _compression = CompressionMethod.None;
              _cookies = new CookieCollection();
              _forConn = new object();
  
gt:             _forEvent = new object();