private async Task ProcessConnection(WebSocketConnectionAsync connection)
      {
         //Fix up the user so it does what we want.
         connection.User.SetSendPlaceholder((message) =>
         {
            if(connection.Client != null)
               connection.AddWrite(connection.Client.WriteMessageAsync(message));
         });
         connection.User.SetCloseSelfPlaceholder(() =>
         {
             if (connection.Client != null)
             {
                 connection.AddClose(connection.Client.WriteRawAsync(WebSocketFrame.GetCloseFrame().GetRawBytes()));
                 connection.Log("This connection was forced to close.", LogLevel.Warning);
             }
         });

         string error = "";
         DataStatus dataStatus;
         HTTPClientHandshake readHandshake;
         WebSocketFrame readFrame;
         byte[] tempBytes;

         connection.State = WebSocketState.Startup;

         while (true)
         {
            //In the beginning, we wait for a handshake dawg.
            if (connection.State == WebSocketState.Startup)
            {
               Tuple<DataStatus, HTTPClientHandshake, string> handshakeResult = await connection.Client.ReadHandshakeAsync();
               dataStatus = handshakeResult.Item1;
               readHandshake = handshakeResult.Item2;
               error = handshakeResult.Item3;

               //Wow, we got a real thing! Let's see if the header is what we need!
               if (dataStatus == DataStatus.Complete)
               {
                  if (readHandshake.Service != settings.Service)
                  {
                     connection.AddWrite(connection.Client.WriteHandshakeAsync(HTTPServerHandshake.GetBadRequest()));
                     break;
                  }

                  //Generate a responding handshake, but strip all extensions and protocols.
                  HTTPServerHandshake response = HTTPServerHandshake.GetResponseForClientHandshake(readHandshake);
                  response.AcceptedProtocols.Clear();
                  response.AcceptedExtensions.Clear();

                  connection.AddWrite(connection.Client.WriteHandshakeAsync(response));
                  connection.State = WebSocketState.Connected;
                  connection.LastTest = DateTime.Now;
                  connection.Log("WebSocket handshake complete", LogLevel.Debug);
               }
               //Hmm, if it's not complete and we're not waiting, it's an error. Close the connection?
               else
               {
                  connection.LogStatus(dataStatus, "Handshake");

                  if (!string.IsNullOrWhiteSpace(error))
                     connection.Log("Extra handshake error information: " + error);

                  //Oohhh it was the CLIENT trying to make us do something we don't like! OK then,
                  //let's tell them why they suck!
                  if (dataStatus == DataStatus.DataFormatError)
                     connection.AddWrite(connection.Client.WriteHandshakeAsync(HTTPServerHandshake.GetBadRequest()));

                  break;
               }
            }
            else if (connection.State == WebSocketState.Connected)
            {
               Tuple<DataStatus, WebSocketFrame> frameResult = await connection.Client.ReadFrameAsync();
               dataStatus = frameResult.Item1;
               readFrame = frameResult.Item2;

               //Ah, we got a full frame from the client! Let's see what it is
               if (dataStatus == DataStatus.Complete)
               {
                  string frameMessage = "";
                  bool continueConnection = connection.ProcessFrame(readFrame, out tempBytes, out frameMessage);

                  if (tempBytes != null)
                     connection.AddWrite(connection.Client.WriteRawAsync(tempBytes));
                  if (!continueConnection)
                     break;
                  if(!string.IsNullOrEmpty(frameMessage))
                     await Task.Run(() => connection.User.ReceivedMessage(frameMessage));
               }
               //Oh something went wrong. That's OK I guess.
               else
               {
                  connection.LogStatus(dataStatus, "Read");
                  break;
               }
            }
         }

         //Now that we're ending, try to dump out a bit of the write queue.
         connection.Log("Connection finished.", LogLevel.Debug);
         connection.User.ClosedConnection();
         RemoveConnection(connection, false);
      }
      public async Task StartAsync()
      {
         //OY! Don't call us again!
         if (server != null)
            return;

         server = new TcpListener(System.Net.IPAddress.Any, settings.Port);

         try
         {
            server.Start();
         }
         catch(Exception e)
         {
            Log("Couldn't start base server: " + e.Message, LogLevel.FatalError);
            return;
         }

         running = true;
         Log("Started server on port: " + settings.Port);

         while (running)
         {
            //Accept the client and set it up
            try
            {
               TcpClient client = await server.AcceptTcpClientAsync();
               client.ReceiveBufferSize = settings.ReceiveBufferSize;
               client.SendBufferSize = settings.SendBufferSize;
               client.SendTimeout = client.ReceiveTimeout = (int)settings.ReadWriteTimeout.TotalMilliseconds;
               WebSocketClient webClient = new WebSocketClient(client, settings.MaxReceiveSize);

               Log("Accepted connection from " + client.Client.RemoteEndPoint);

               //Start up a spinner to handle this new connection. The spinner will take care of headers and all that,
               //we're just here to intercept new connections.
               WebSocketConnectionAsync connection = 
                  new WebSocketConnectionAsync(webClient, GenerateNewUser(), settings.LogProvider);
               connection.Awaitable = ProcessConnection(connection);

               lock (connectionLock)
               {
                  connections.Add(connection);
               }
            }
            catch(Exception e)
            {
               if (e is ObjectDisposedException)
                  Log("Connection accepter has gone away it seems...", LogLevel.Debug);
               else
                  Log("Encountered exception while accepting: " + e, LogLevel.Error);
            }
         }

         running = false;
      }
      /// <summary>
      /// Remove and cleanup the given spinner
      /// </summary>
      /// <param name="spinner">Spinner.</param>
      private void RemoveConnection(WebSocketConnectionAsync connection, bool wait = true)
      {
         bool removed = false;

         lock (connectionLock)
         {
            removed = connections.Remove(connection);
         }

         if (removed)
         {
            connection.Client.CancelAsyncOperations();

            if (!wait || connection.Awaitable.Wait(settings.ShutdownTimeout))
               Log("Removed connection: " + connection.ID, LogLevel.Debug);
            else
               Log("Connection " + connection.ID + " didn't shut down properly! You have a dangling connection!", LogLevel.Error);

            connection.Dispose();
         }
      }