public void ProcessRequest(HttpApplication webapp)
        {
            webapp.HttpResponse.Server = "Microsoft .Net Terrarium";
            webapp.HttpResponse.Date = DateTime.Now;
            webapp.HttpResponse.ContentType = "text/xml";
            webapp.HttpResponse.StatusCode = HttpStatusCode.OK;
            webapp.HttpResponse.StatusDescription = "OK";
            webapp.HttpResponse.KeepAlive = false;
            string body;

            if (webapp.HttpRequest.Method == "GET")
            {
                body = "<version><build>" + peerVersion.Build + "</build>";
                body += "<major>" + peerVersion.Major + "</major>\t";
                body += "<minor>" + peerVersion.Minor + "</minor>\t</version>";
                body += "<channel>" + GameEngine.Current.PeerChannel + "</channel>";
            }
            else
            {
                webapp.HttpResponse.StatusCode = HttpStatusCode.MethodNotAllowed;
                webapp.HttpResponse.StatusDescription = "Method Not Allowed";
                body = "<HTML><BODY>" + "The method " + webapp.HttpRequest.Method;
                body += " is not allowed.</BODY></HTML>";
                webapp.HttpResponse.ContentType = "text/html";
            }

            // Encode the body message and place it on the stream.
            var bodyBytes = Encoding.ASCII.GetBytes(body);
            webapp.HttpResponse.ContentLength = bodyBytes.Length;
            webapp.HttpResponse.Close(bodyBytes);
        }
        /// <summary>
        ///  Start listening on the given host IP Address, on the given
        ///  port.  
        /// </summary>
        /// <param name="hostIP">The host's IP address to bind to.</param>
        /// <param name="port">The port to bind on.</param>
        public void Start(string hostIP, int port)
        {
            HttpTraceHelper.ExceptionCaught.Level = TraceLevel.Verbose;

            _listener = new HttpWebListener();
            _listener.Start(port);

            // Put this in a loop if we want more listeners in the pool
            var stateObject = new HttpApplication();
            _listener.BeginGetRequest(_getRequestCB, stateObject);
        }
 /// <summary>
 ///  Used to handle a request where the method is supported
 ///  but insufficient data is available.  The primary culprit
 ///  here is a POST operation with no POST data.
 /// </summary>
 /// <param name="state">The web application state object for this request.</param>
 /// <param name="message">The message to be sent to the client to describe the failure.</param>
 public void HandleBadRequest(HttpApplication state, string message)
 {
     state.HttpResponse.StatusCode = HttpStatusCode.BadRequest;
     state.HttpResponse.StatusDescription = "Bad Request";
     state.HttpResponse.Server = "Microsoft .Net Terrarium";
     state.HttpResponse.Date = DateTime.Now;
     state.HttpResponse.ContentType = "text/html";
     state.HttpResponse.KeepAlive = false;
     var body = message;
     var bodyBytes = Encoding.ASCII.GetBytes(body);
     state.HttpResponse.ContentLength = bodyBytes.Length;
     state.HttpResponse.Close(bodyBytes);
 }
        /// <summary>
        ///  Handles a namespace that isn't currently bound by this namespace
        ///  manager.  This could happen because of case sensitivity issues, trailing
        ///  path characters or any other string morph that causes the namespace
        ///  to not match one that is currently registered.  This should only happen
        ///  through a failed user connection using a web browser and a mistyped path.
        /// </summary>
        /// <param name="state">The web application state for the current connection.</param>
        public void HandleUnsupportedNamespace(HttpApplication state)
        {
            state.HttpResponse.StatusCode = HttpStatusCode.OK;
            state.HttpResponse.StatusDescription = "OK";
            state.HttpResponse.Server = "Microsoft .Net Terrarium";
            state.HttpResponse.Date = DateTime.Now;
            state.HttpResponse.ContentType = "text/html";
            state.HttpResponse.KeepAlive = false;

            var body = "<HTML><BODY>Unsupported URI.</BODY></HTML>";

            var bodyBytes = Encoding.ASCII.GetBytes(body);
            state.HttpResponse.ContentLength = bodyBytes.Length;
            state.HttpResponse.Close(bodyBytes);
        }
        /// <summary>
        ///  Handles a method that is not supported by the current
        ///  namespace implementation.  This happens whenever a users
        ///  requests a namespace using a method that isn't valid.  This
        ///  should only happen if Terrarium's of differing versions
        ///  connect to one another, or someone hits the peer with
        ///  a web browser and changes the Method to something other than
        ///  GET or POST.
        /// </summary>
        /// <param name="state">The web server state object for the connection.</param>
        public void HandleUnsupportedMethod(HttpApplication state)
        {
            state.HttpResponse.StatusCode = HttpStatusCode.MethodNotAllowed;
            state.HttpResponse.StatusDescription = "Method Not Allowed";
            state.HttpResponse.Server = "Microsoft .Net Terrarium";
            state.HttpResponse.Date = DateTime.Now;
            state.HttpResponse.ContentType = "text/html";
            state.HttpResponse.KeepAlive = false;

            var body = "<HTML><BODY>" + "The method " + state.HttpRequest.Method;
            body += " is not allowed.</BODY></HTML>";

            var bodyBytes = Encoding.ASCII.GetBytes(body);
            state.HttpResponse.ContentLength = bodyBytes.Length;
            state.HttpResponse.Close(bodyBytes);
        }
        /// <summary>
        ///  This method receives requests from other peers and maps the URI
        ///  namespace or resource name to an actual namespace handler.  If one
        ///  exists then the namespace handler is invoked to process the request.
        ///  If not some default processing is used.
        /// </summary>
        /// <param name="asyncResult">The Async object for the request.</param>
        public void GetRequestCallback(IAsyncResult asyncResult)
        {
            try
            {
                OnBeforeProcessRequest();

                var stateObject = asyncResult.AsyncState as HttpApplication;
                stateObject.HttpRequest = _listener.EndGetRequest(asyncResult);

                if (stateObject.HttpRequest.Method == "GET")
                {
                    var ns = stateObject.HttpRequest.RequestUri.Segments[1];
                    if (_nsModules.Contains(ns))
                    {
                        var nsHandler = (IHttpNamespaceHandler) _nsModules[ns];
                        nsHandler.ProcessRequest(stateObject);
                    }
                    else
                    {
                        HandleUnsupportedNamespace(stateObject);
                    }
                }
                else if (stateObject.HttpRequest.Method == "POST")
                {
                    if (stateObject.HttpRequest.ContentLength <= 0)
                    {
                        var message = "<html><body>Bad Request - POST with no data";
                        message += "</body></html>";
                        HandleBadRequest(stateObject, message);
                    }
                    else
                    {
                        stateObject.RequestStream = stateObject.HttpRequest.GetRequestStream();
                        try
                        {
                            stateObject.RequestStream.BeginRead(stateObject.ReadBuffer, 0, stateObject.ReadBuffer.Length,
                                                                _readCB, stateObject);
                        }
                        catch (Exception exception)
                        {
#if DEBUG
                            if (HttpTraceHelper.ExceptionCaught.TraceVerbose)
                            {
                                HttpTraceHelper.WriteLine("Caught exception:" + exception);
                            }
#endif
                        }
                    }
                }
                else
                {
                    HandleUnsupportedNamespace(stateObject);
                }

                // Queue up another _listener
                var newStateObject = new HttpApplication();
                _listener.BeginGetRequest(_getRequestCB, newStateObject);
            }
            catch (Exception ex)
            {
#if DEBUG
                if (HttpTraceHelper.ExceptionCaught.TraceVerbose)
                {
                    HttpTraceHelper.WriteLine("Caught exception:" + ex);
                }
#endif
                var stateObject = asyncResult.AsyncState as HttpApplication;
                stateObject.Reset();
                _listener.BeginGetRequest(_getRequestCB, stateObject);
            }
            finally
            {
                OnAfterProcessRequest();
            }
        }
        /// <summary>
        ///  Processes the HTTP Request.  This handler is capable of
        ///  processing several different messages and a series of
        ///  conditional logic is used to determine which message
        ///  is being invoked.
        /// </summary>
        /// <param name="webapp">The web application object for the request.</param>
        public void ProcessRequest(HttpApplication webapp)
        {
            // Initiailize any locals.  This sets up a basic successful
            // response and cahces the requested namespace for the conditional
            // logic.
            var requestedNamespace = webapp.HttpRequest.RequestUri.AbsolutePath;
            webapp.HttpResponse.Server = "Microsoft .Net Terrarium";
            webapp.HttpResponse.Date = DateTime.Now;
            webapp.HttpResponse.ContentType = "text/xml";
            webapp.HttpResponse.StatusCode = HttpStatusCode.OK;
            webapp.HttpResponse.StatusDescription = "OK";
            webapp.HttpResponse.KeepAlive = false;
            var failureReason = "none";
            string body;

            if (webapp.HttpRequest.Method == "GET")
            {
                // Code to implement the GET method.  The /organisms/stats namespace
                // is the important namespace here, and all other namespaces return
                // an error.

                if (requestedNamespace == "/organisms/stats")
                {
                    // Gets XML statistics information from the
                    // network engine.
                    body = _engine.GetNetworkStatistics();
                }
                else
                {
                    body = "<HTML><BODY>" + "Sorry, GET is not supported for ";
                    body += webapp.HttpRequest.RequestUri.ToString();
                    body += "</BODY></HTML>";
                    webapp.HttpResponse.ContentType = "text/html";
                    // Return an error stream.  The namespace being requested
                    // doesn't actually exist.  This is a BadRequest
                    webapp.HttpResponse.StatusCode = HttpStatusCode.BadRequest;
                }
            }
            else if (webapp.HttpRequest.Method == "POST")
            {
                // Code to implement the POST method.  Most of the resources
                // provided by the OrganismNamespaceHandler have to be
                // retrieved using the POST method.

                // Prepares a binary formatter to serialize/deserialize
                // state information.
                var channel = new BinaryFormatter();

                // Add a special binder to the BinaryFormatter to ensure that
                // the stream hasn't been hacked to try to get us to instantiate an
                // object that the organism shouldn't be able to access
                channel.Binder = new TeleportStateBinder();
                TeleportState theOrganism = null;

                if (requestedNamespace == "/organisms/state")
                {
                    _engine.WriteProtocolInfo("/organisms/state: Start receiving TeleportState.");

                    // Provides an implementation for the /organisms/state
                    // resource.  This resource handles the retrieval of
                    // a state object that will be placed into the game
                    // engine (Step 4 of the conversation).

                    var exceptionOccurred = false;
                    var ipAddress = webapp.HttpRequest.RemoteEndPoint.Address.ToString();

                    // If they aren't on the same channel, set the exception bit
                    // this will cause the teleportation to fail
                    if (webapp.HttpRequest.Headers["peerChannel"].ToUpper(CultureInfo.InvariantCulture) !=
                        GameEngine.Current.PeerChannel.ToUpper(CultureInfo.InvariantCulture))
                    {
                        exceptionOccurred = true;
                        failureReason = "Peer channel mismatch";
                        _engine.WriteProtocolInfo("/organisms/state: Sender is wrong peer channel. Denied.");
                    }

                    if (_engine.PeerManager.BadPeer(ipAddress) || !_engine.PeerManager.ShouldReceive(ipAddress))
                    {
                        exceptionOccurred = true;
                        failureReason = "The peer " + ipAddress +
                                        " did not pass the check for badpeer/shouldreceive on the remote peer";
                        _engine.WriteProtocolInfo(
                            "/organisms/state: Sender is marked as a bad peer or is sending too often. Denied.");
                    }
                    else
                    {
                        try
                        {
                            theOrganism = (TeleportState) channel.Deserialize(webapp.Buffer);
                        }
                        catch (Exception e)
                        {
                            ErrorLog.LogHandledException(e);
                            GameEngine.Current.NetworkEngine.LastTeleportationException = e.ToString();
                            exceptionOccurred = true;
                            failureReason = "Exception occured during deserialization of the organism state";
                        }
                    }

                    if (!exceptionOccurred)
                    {
                        _engine.WriteProtocolInfo("/organisms/state: TeleportState successfully deserialized.");

                        // Check to see if the assembly is installed locally
                        Debug.Assert(GameEngine.Current != null);
                        Debug.Assert(theOrganism.OrganismState != null);
                        Debug.Assert(theOrganism.OrganismState.Species != null);
                        Debug.Assert(((Species) theOrganism.OrganismState.Species).AssemblyInfo != null);
                        if (
                            GameEngine.Current.Pac.Exists(
                                ((Species) theOrganism.OrganismState.Species).AssemblyInfo.FullName))
                        {
                            _engine.WriteProtocolInfo("/organisms/state: Assembly exists, add organism to game.");

                            // Add the teleported organism to the game
                            GameEngine.Current.ReceiveTeleportation(theOrganism, false);

                            // Let the peer know that we don't need the assembly
                            body = "<assemblyreceived>true</assemblyreceived>";
                        }
                        else
                        {
                            _engine.WriteProtocolInfo(
                                "/organisms/state: Assembly doesn't exist, don't add organism to game.");

                            // Let the peer know that we'll need the assembly
                            body = "<assemblyreceived>false</assemblyreceived>";
                        }

                        _engine.PeerManager.SetReceive(ipAddress);
                    }
                    else
                    {
                        _engine.WriteProtocolInfo("/organisms/state: Problem occurred:" + failureReason);

                        body = "<organismArrived>false</organismArrived><reason>" + failureReason + "</reason>";
                        GameEngine.Current.NetworkEngine.CountFailedTeleportationReceives();
                    }
                }
                else if (requestedNamespace == "/organisms/assemblies")
                {
                    _engine.WriteProtocolInfo("/organisms/assemblies: Start receiving organism assembly");

                    // Someone is sending us an assembly to save
                    try
                    {
                        var ipAddress = webapp.HttpRequest.RemoteEndPoint.Address.ToString();
                        if (_engine.PeerManager.BadPeer(ipAddress) || !_engine.PeerManager.ShouldReceive(ipAddress))
                        {
                            _engine.WriteProtocolInfo(
                                "/organisms/assemblies: Sender is marked as a bad peer or is sending too often. Denied.");
                            body = "<assemblysaved>false</assemblysaved>";
                        }
                        else
                        {
                            // Write the assembly to a location that is "safe" meaning that it is not
                            // a location that is known or predictable in any way.  This prevents an attack
                            // where an assembly is sent to this machine with malicious code in it and saved
                            // in a known location that can be used at a later time.
                            var tempFile = PrivateAssemblyCache.GetSafeTempFileName();
                            using (Stream fileStream = File.OpenWrite(tempFile))
                            {
                                var bufferBytes = webapp.Buffer.GetBuffer();
                                fileStream.Write(bufferBytes, 0, bufferBytes.Length);
                            }

                            // Now save the assembly in the Private Assembly Cache
                            var assemblyFullName = webapp.HttpRequest.Headers["Assembly"];
                            try
                            {
                                GameEngine.Current.Pac.SaveOrganismAssembly(tempFile, assemblyFullName);
                                _engine.WriteProtocolInfo("/organisms/assemblies: Assembly saved in PAC.");
                            }
                            catch (Exception e)
                            {
                                // The assembly could fail validation
                                ErrorLog.LogHandledException(e);
                                GameEngine.Current.NetworkEngine.LastTeleportationException = e.ToString();
                                GameEngine.Current.NetworkEngine.CountFailedTeleportationReceives();
                            }

                            File.Delete(tempFile);

                            body = "<assemblysaved>true</assemblysaved>";
                        }
                    }
                    catch (Exception ex)
                    {
                        ErrorLog.LogHandledException(ex);
                        body = "<assemblysaved>false</assemblysaved>";
                        GameEngine.Current.NetworkEngine.LastTeleportationException = ex.ToString();
                        GameEngine.Current.NetworkEngine.CountFailedTeleportationReceives();
                    }
                }
                else if (requestedNamespace == "/organisms/assemblycheck")
                {
                    _engine.WriteProtocolInfo("/organisms/assemblycheck: Checking to see if we have an assembly.");

                    // Check to see if the assembly is installed locally
                    var reader = new StreamReader(webapp.Buffer, Encoding.ASCII);
                    var assemblyName = reader.ReadToEnd();

                    Debug.Assert(GameEngine.Current != null);
                    if (GameEngine.Current.Pac.Exists(assemblyName))
                    {
                        // Let the peer know that we don't need the assembly
                        _engine.WriteProtocolInfo("/organisms/assemblycheck: We have it.");
                        body = "<assemblyexists>true</assemblyexists>";
                    }
                    else
                    {
                        // Let the peer know that we need the assembly
                        _engine.WriteProtocolInfo("/organisms/assemblycheck: Don't have it.");
                        body = "<assemblyexists>false</assemblyexists>";
                    }
                }
                else
                {
                    // Handles unsupported namespaces.  This could have been
                    // offloaded to a helper function in the HttpNamespaceManager.
                    body = "<HTML><BODY>" + "The namespace " + webapp.HttpRequest.RequestUri;
                    body += " is not supported.</BODY></HTML>";
                    webapp.HttpResponse.ContentType = "text/html";
                }
            }
            else
            {
                // Handles rendering of unsupport methods.  This could have been
                // offloaded to a helper function in the HttpNamespaceManager
                // or another class.
                webapp.HttpResponse.StatusCode = HttpStatusCode.MethodNotAllowed;
                webapp.HttpResponse.StatusDescription = "Method Not Allowed";
                body = "<HTML><BODY>" + "The method " + webapp.HttpRequest.Method;
                body += " is not allowed.</BODY></HTML>";
                webapp.HttpResponse.ContentType = "text/html";
            }

            // Encode the body response and output the response.
            var bodyBytes = Encoding.ASCII.GetBytes(body);
            webapp.HttpResponse.ContentLength = bodyBytes.Length;
            webapp.HttpResponse.Close(bodyBytes);
        }
        /// <summary>
        ///  Start listening on the given host IP Address, on the given
        ///  port.  
        /// </summary>
        /// <param name="hostIP">The host's IP address to bind to.</param>
        /// <param name="port">The port to bind on.</param>
        public void Start(string hostIP, int port)
        {
            HttpTraceHelper.ExceptionCaught.Level = TraceLevel.Verbose;
            //TraceHelper.Api.Level = TraceLevel.Verbose;
            //TraceHelper.ExceptionThrown.Level = TraceLevel.Verbose;
            //TraceHelper.InternalLog.Level = TraceLevel.Verbose;
            //TraceHelper.Protocol.Level = TraceLevel.Verbose;
            //TraceHelper.Socket.Level = TraceLevel.Verbose;

            listener = new HttpWebListener();
            listener.Start(port);

            // Put this in a loop if we want more listeners in the pool
            HttpApplication stateObject = new HttpApplication();
            listener.BeginGetRequest(getRequestCB, stateObject);
        }