From 032aeb8b5d05f5f5a8ef8c6e0fe572a321717c35 Mon Sep 17 00:00:00 2001
From: Teravus Ovares
Date: Wed, 29 Jul 2009 02:15:45 +0000
Subject: * Adds the ability to have a thread efficient long poll service (such
 as the eventqueue) * If this doesn't melt the Http Server, this will
 significantly reduce the number of threads in use on regions with many users.
 * Adds AddPollServiceHTTPHandler, and RemovePollServiceHTTPHandler to
 BaseHttpServer * Generic enough to be used for many long poll services, not
 only the EventQueue.

---
 .../Framework/Servers/HttpServer/BaseHttpServer.cs |  95 +++++++++++++-
 .../Servers/HttpServer/Interfaces/IHttpServer.cs   |   5 +
 .../Servers/HttpServer/PollServiceEventArgs.cs     |  53 ++++++++
 .../Servers/HttpServer/PollServiceHttpRequest.cs   |  48 +++++++
 .../HttpServer/PollServiceRequestManager.cs        | 145 +++++++++++++++++++++
 .../Servers/HttpServer/PollServiceWorkerThread.cs  | 100 ++++++++++++++
 OpenSim/Framework/Servers/Tests/OSHttpTests.cs     |   1 +
 7 files changed, 442 insertions(+), 5 deletions(-)
 create mode 100644 OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
 create mode 100644 OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs
 create mode 100644 OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
 create mode 100644 OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs

(limited to 'OpenSim/Framework')

diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index 4532e76..369d7d4 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -64,6 +64,9 @@ namespace OpenSim.Framework.Servers.HttpServer
         protected Dictionary<string, GenericHTTPMethod> m_HTTPHandlers  = new Dictionary<string, GenericHTTPMethod>();
         protected Dictionary<string, IHttpAgentHandler> m_agentHandlers = new Dictionary<string, IHttpAgentHandler>();
 
+        protected Dictionary<string, PollServiceEventArgs> m_pollHandlers =
+            new Dictionary<string, PollServiceEventArgs>();
+
         protected uint m_port;
         protected uint m_sslport;
         protected bool m_ssl;
@@ -72,6 +75,8 @@ namespace OpenSim.Framework.Servers.HttpServer
 
         protected IPAddress m_listenIPAddress = IPAddress.Any;
 
+        private PollServiceRequestManager m_PollServiceManager;
+
         public uint SSLPort
         {
             get { return m_sslport; }
@@ -189,6 +194,26 @@ namespace OpenSim.Framework.Servers.HttpServer
             return false;
         }
 
+        public bool AddPollServiceHTTPHandler(string methodName, GenericHTTPMethod handler, PollServiceEventArgs args)
+        {
+            bool pollHandlerResult = false;
+            lock (m_pollHandlers)
+            {
+                if (!m_pollHandlers.ContainsKey( methodName))
+                {
+                    m_pollHandlers.Add(methodName,args);
+                    pollHandlerResult = true;
+                    
+                }
+            }
+            
+            if (pollHandlerResult)
+                return AddHTTPHandler(methodName, handler);
+
+            return false;
+            
+        }
+
         // Note that the agent string is provided simply to differentiate
         // the handlers - it is NOT required to be an actual agent header
         // value.
@@ -230,8 +255,19 @@ namespace OpenSim.Framework.Servers.HttpServer
         {
             IHttpClientContext context = (IHttpClientContext)source;
             IHttpRequest request = args.Request;
+            
 
-            OnHandleRequestIOThread(context,request);
+            PollServiceEventArgs psEvArgs;
+            if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs))
+            {
+                
+                m_PollServiceManager.Enqueue(new PollServiceHttpRequest(psEvArgs, context, request));
+                //DoHTTPGruntWork(psEvArgs.NoEvents(),new OSHttpResponse(new HttpResponse(context, request)));
+            }
+            else
+            {
+                OnHandleRequestIOThread(context, request);
+            }
 
         }
 
@@ -341,7 +377,7 @@ namespace OpenSim.Framework.Servers.HttpServer
                         string requestBody = reader.ReadToEnd();
 
                         reader.Close();
-                        requestStream.Close();
+                        //requestStream.Close();
 
                         Hashtable keysvals = new Hashtable();
                         Hashtable headervals = new Hashtable();
@@ -527,6 +563,36 @@ namespace OpenSim.Framework.Servers.HttpServer
             }
         }
 
+        private bool TryGetPollServiceHTTPHandler(string handlerKey, out PollServiceEventArgs oServiceEventArgs)
+        {
+            string bestMatch = null;
+
+            lock (m_pollHandlers)
+            {
+                foreach (string pattern in m_pollHandlers.Keys)
+                {
+                    if (handlerKey.StartsWith(pattern))
+                    {
+                        if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
+                        {
+                            bestMatch = pattern;
+                        }
+                    }
+                }
+
+                if (String.IsNullOrEmpty(bestMatch))
+                {
+                    oServiceEventArgs = null;
+                    return false;
+                }
+                else
+                {
+                    oServiceEventArgs = m_pollHandlers[bestMatch];
+                    return true;
+                }
+            }
+        }
+
         private bool TryGetHTTPHandler(string handlerKey, out GenericHTTPMethod HTTPHandler)
         {
             //m_log.DebugFormat("[BASE HTTP HANDLER]: Looking for HTTP handler for {0}", handlerKey);
@@ -822,7 +888,7 @@ namespace OpenSim.Framework.Servers.HttpServer
                 {
                     response.Send();
                     response.OutputStream.Flush();
-                    response.OutputStream.Close();
+                    //response.OutputStream.Close();
                 }
                 catch (IOException e)
                 {
@@ -1237,7 +1303,7 @@ namespace OpenSim.Framework.Servers.HttpServer
             }
         }
 
-        private static void DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response)
+        internal void DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response)
         {
             //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response");
             int responsecode = (int)responsedata["int_response_code"];
@@ -1261,7 +1327,7 @@ namespace OpenSim.Framework.Servers.HttpServer
             }
             //Even though only one other part of the entire code uses HTTPHandlers, we shouldn't expect this
             //and should check for NullReferenceExceptions
-
+            
             if (string.IsNullOrEmpty(contentType))
             {
                 contentType = "text/html";
@@ -1402,6 +1468,8 @@ namespace OpenSim.Framework.Servers.HttpServer
             //m_workerThread.Start();
             //ThreadTracker.Add(m_workerThread);
             StartHTTP();
+            
+
         }
 
         private void StartHTTP()
@@ -1434,6 +1502,9 @@ namespace OpenSim.Framework.Servers.HttpServer
                 m_httpListener2.RequestReceived += OnRequest;
                 //m_httpListener.Start();
                 m_httpListener2.Start(64);
+
+                // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events
+                m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000);
                 HTTPDRunning = true;
 
                 //HttpListenerContext context;
@@ -1514,6 +1585,20 @@ namespace OpenSim.Framework.Servers.HttpServer
             }
         }
 
+        public void RemovePollServiceHTTPHandler(string httpMethod, string path)
+        {
+            lock (m_pollHandlers)
+            {
+                if (m_pollHandlers.ContainsKey(httpMethod))
+                {
+                    m_pollHandlers.Remove(httpMethod);
+                }
+            }
+
+            RemoveHTTPHandler(httpMethod, path);
+            
+        }
+
         public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler)
         {
             try
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
index c415dfb..9095831 100644
--- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
@@ -74,6 +74,9 @@ namespace OpenSim.Framework.Servers.HttpServer
         /// </returns>
         bool AddHTTPHandler(string methodName, GenericHTTPMethod handler);
 
+
+        bool AddPollServiceHTTPHandler(string methodName, GenericHTTPMethod handler, PollServiceEventArgs args);
+
         /// <summary>
         /// Adds a LLSD handler, yay.
         /// </summary>
@@ -114,6 +117,8 @@ namespace OpenSim.Framework.Servers.HttpServer
         /// <param name="httpMethod"></param>
         /// <param name="path"></param>
         void RemoveHTTPHandler(string httpMethod, string path);
+
+        void RemovePollServiceHTTPHandler(string httpMethod, string path);
         
         bool RemoveLLSDHandler(string path, LLSDMethod handler);
         
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
new file mode 100644
index 0000000..fed490e
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections;
+using OpenMetaverse;
+namespace OpenSim.Framework.Servers.HttpServer
+{
+    public delegate bool HasEventsMethod(UUID pId);
+
+    public delegate Hashtable GetEventsMethod(UUID pId, string request);
+
+    public delegate Hashtable NoEventsMethod();
+
+    public class PollServiceEventArgs : EventArgs
+    {
+        public HasEventsMethod HasEvents;
+        public GetEventsMethod GetEvents;
+        public NoEventsMethod NoEvents;
+        public UUID Id;
+        public PollServiceEventArgs(HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents,UUID pId)
+        {
+            HasEvents = pHasEvents;
+            GetEvents = pGetEvents;
+            NoEvents = pNoEvents;
+            Id = pId;
+        }
+    }
+}
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs
new file mode 100644
index 0000000..ff7c1e8
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using HttpServer;
+
+namespace OpenSim.Framework.Servers.HttpServer
+{
+
+    public class PollServiceHttpRequest
+    {
+        public readonly PollServiceEventArgs PollServiceArgs;
+        public readonly IHttpClientContext HttpContext;
+        public readonly IHttpRequest Request;
+        public readonly int RequestTime;
+        public PollServiceHttpRequest(PollServiceEventArgs pPollServiceArgs, IHttpClientContext pHttpContext, IHttpRequest pRequest)
+        {
+            PollServiceArgs = pPollServiceArgs;
+            HttpContext = pHttpContext;
+            Request = pRequest;
+            RequestTime = System.Environment.TickCount;
+        }
+    }
+}
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
new file mode 100644
index 0000000..7f632cf
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections;
+using System.Threading;
+using HttpServer;
+
+namespace OpenSim.Framework.Servers.HttpServer
+{
+    public class PollServiceRequestManager
+    {
+        private readonly BaseHttpServer m_server;
+        private static Queue m_requests = Queue.Synchronized(new Queue());
+        private uint m_WorkerThreadCount = 0;
+        private Thread[] m_workerThreads;
+        private PollServiceWorkerThread[] m_PollServiceWorkerThreads;
+        private Thread m_watcherThread;
+        private bool m_running = true;
+
+        
+
+        public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout)
+        {
+            m_server = pSrv;
+            m_WorkerThreadCount = pWorkerThreadCount;
+            m_workerThreads = new Thread[m_WorkerThreadCount];
+            m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount];
+            m_watcherThread = new Thread(ThreadStart);
+
+            
+            //startup worker threads
+            for (uint i=0;i<m_WorkerThreadCount;i++)
+            {
+                m_PollServiceWorkerThreads[i] = new PollServiceWorkerThread(m_server, pTimeout);
+                m_PollServiceWorkerThreads[i].ReQueue += ReQueueEvent;
+               
+                m_workerThreads[i] = new Thread( m_PollServiceWorkerThreads[i].ThreadStart);
+                m_workerThreads[i].Name = String.Format("PollServiceWorkerThread{0}",i);
+                //Can't add to thread Tracker here Referencing OpenSim.Framework creates circular reference
+                m_workerThreads[i].Start();
+                
+            }
+            //start watcher threads
+            m_watcherThread.Name = "PollServiceWatcherThread";
+            m_watcherThread.Start();
+
+
+        }
+
+        internal void ReQueueEvent(PollServiceHttpRequest req)
+        {
+            // Do accounting stuff here
+            Enqueue(req);
+        }
+
+        public void Enqueue(PollServiceHttpRequest req)
+        {
+            lock (m_requests)
+                m_requests.Enqueue(req);
+        }
+
+        public void ThreadStart(object o)
+        {
+            while (m_running)
+            {
+                ProcessQueuedRequests();
+                Thread.Sleep(1000);
+            }
+        }
+
+        private void ProcessQueuedRequests()
+        {
+            lock (m_requests)
+            {
+                if (m_requests.Count == 0)
+                    return;
+
+                int reqperthread = (int) (m_requests.Count/m_WorkerThreadCount) + 1;
+                // For Each WorkerThread
+                for (int tc = 0; tc < m_WorkerThreadCount && m_requests.Count > 0; tc++)
+                {
+                    //Loop over number of requests each thread handles.
+                    for (int i=0;i<reqperthread && m_requests.Count > 0;i++)
+                    {
+                        try
+                        {
+                            m_PollServiceWorkerThreads[tc].Enqueue((PollServiceHttpRequest)m_requests.Dequeue());
+                        }
+                        catch (InvalidOperationException)
+                        {
+                            // The queue is empty, we did our calculations wrong!
+                            return;
+                        }
+                        
+                    }
+                }
+            }
+            
+        }
+
+
+
+        ~PollServiceRequestManager()
+        {
+            foreach (object o in m_requests)
+            {
+                PollServiceHttpRequest req = (PollServiceHttpRequest) o;
+                m_server.DoHTTPGruntWork(req.PollServiceArgs.NoEvents(), new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request)));
+            }
+
+            m_requests.Clear();
+
+            foreach (Thread t in m_workerThreads)
+            {
+                t.Abort();
+            }
+            m_running = false;
+        }
+    }
+}
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs
new file mode 100644
index 0000000..4c0be78
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System.IO;
+using System.Text;
+using HttpServer;
+using OpenMetaverse;
+
+namespace OpenSim.Framework.Servers.HttpServer
+{
+    public delegate void ReQueuePollServiceItem(PollServiceHttpRequest req);
+    
+    public class PollServiceWorkerThread
+    {
+        public event ReQueuePollServiceItem ReQueue;
+
+        private readonly BaseHttpServer m_server;
+        private BlockingQueue<PollServiceHttpRequest> m_request;
+        private bool m_running = true;
+        private int m_timeout = 25000;
+
+        
+
+        public PollServiceWorkerThread(BaseHttpServer pSrv, int pTimeout)
+        {
+            m_request = new BlockingQueue<PollServiceHttpRequest>();
+            m_server = pSrv;
+            m_timeout = pTimeout;
+        }
+
+        public void ThreadStart(object o)
+        {
+            Run();
+        }
+
+        public void Run()
+        {
+            while (m_running)
+            {
+                PollServiceHttpRequest req = m_request.Dequeue();
+                if (req.PollServiceArgs.HasEvents(req.PollServiceArgs.Id))
+                {
+                    StreamReader str = new StreamReader(req.Request.Body);
+
+                    Hashtable responsedata = req.PollServiceArgs.GetEvents(req.PollServiceArgs.Id, str.ReadToEnd());
+                    m_server.DoHTTPGruntWork(responsedata,
+                                             new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request)));
+                }
+                else
+                {
+                    if ((Environment.TickCount - req.RequestTime) > m_timeout)
+                    {
+                        m_server.DoHTTPGruntWork(req.PollServiceArgs.NoEvents(),
+                                                 new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request)));
+                    }
+                    else
+                    {
+                        ReQueuePollServiceItem reQueueItem = ReQueue;
+                        if (reQueueItem != null)
+                            reQueueItem(req);
+                    }
+                }
+            }
+
+
+        }
+
+        internal void Enqueue(PollServiceHttpRequest pPollServiceHttpRequest)
+        {
+            m_request.Enqueue(pPollServiceHttpRequest);
+        }
+    }
+}
diff --git a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
index f7f0afa..a6a90dc 100644
--- a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
+++ b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
@@ -67,6 +67,7 @@ namespace OpenSim.Framework.Servers.Tests
             public void Send(byte[] buffer) {}
             public void Send(byte[] buffer, int offset, int size) {}
             public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body, string contentType) {}
+            public void Close() { }
 
             public event EventHandler<DisconnectedEventArgs> Disconnected = delegate { };
             /// <summary>
-- 
cgit v1.1