aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Servers/HttpServer
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework/Servers/HttpServer')
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs90
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs19
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs241
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs165
4 files changed, 270 insertions, 245 deletions
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index dfdd566..97035e3 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -395,6 +395,7 @@ namespace OpenSim.Framework.Servers.HttpServer
395 StreamReader reader = new StreamReader(requestStream, encoding); 395 StreamReader reader = new StreamReader(requestStream, encoding);
396 396
397 string requestBody = reader.ReadToEnd(); 397 string requestBody = reader.ReadToEnd();
398 reader.Close();
398 399
399 Hashtable keysvals = new Hashtable(); 400 Hashtable keysvals = new Hashtable();
400 Hashtable headervals = new Hashtable(); 401 Hashtable headervals = new Hashtable();
@@ -736,7 +737,7 @@ namespace OpenSim.Framework.Servers.HttpServer
736 // Every month or so this will wrap and give bad numbers, not really a problem 737 // Every month or so this will wrap and give bad numbers, not really a problem
737 // since its just for reporting 738 // since its just for reporting
738 int tickdiff = requestEndTick - requestStartTick; 739 int tickdiff = requestEndTick - requestStartTick;
739 if (tickdiff > 3000 && requestHandler != null && requestHandler.Name != "GetTexture") 740 if (tickdiff > 3000 && (requestHandler == null || requestHandler.Name == null || requestHandler.Name != "GetTexture"))
740 { 741 {
741 m_log.InfoFormat( 742 m_log.InfoFormat(
742 "[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms", 743 "[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms",
@@ -1657,10 +1658,40 @@ namespace OpenSim.Framework.Servers.HttpServer
1657 1658
1658 internal byte[] DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response) 1659 internal byte[] DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response)
1659 { 1660 {
1660 //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response"); 1661 int responsecode;
1661 int responsecode = (int)responsedata["int_response_code"]; 1662 string responseString = String.Empty;
1662 string responseString = (string)responsedata["str_response_string"]; 1663 byte[] responseData = null;
1663 string contentType = (string)responsedata["content_type"]; 1664 string contentType;
1665
1666 if (responsedata == null)
1667 {
1668 responsecode = 500;
1669 responseString = "No response could be obtained";
1670 contentType = "text/plain";
1671 responsedata = new Hashtable();
1672 }
1673 else
1674 {
1675 try
1676 {
1677 //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response");
1678 responsecode = (int)responsedata["int_response_code"];
1679 if (responsedata["bin_response_data"] != null)
1680 responseData = (byte[])responsedata["bin_response_data"];
1681 else
1682 responseString = (string)responsedata["str_response_string"];
1683 contentType = (string)responsedata["content_type"];
1684 if (responseString == null)
1685 responseString = String.Empty;
1686 }
1687 catch
1688 {
1689 responsecode = 500;
1690 responseString = "No response could be obtained";
1691 contentType = "text/plain";
1692 responsedata = new Hashtable();
1693 }
1694 }
1664 1695
1665 if (responsedata.ContainsKey("error_status_text")) 1696 if (responsedata.ContainsKey("error_status_text"))
1666 { 1697 {
@@ -1705,25 +1736,40 @@ namespace OpenSim.Framework.Servers.HttpServer
1705 1736
1706 response.AddHeader("Content-Type", contentType); 1737 response.AddHeader("Content-Type", contentType);
1707 1738
1739 if (responsedata.ContainsKey("headers"))
1740 {
1741 Hashtable headerdata = (Hashtable)responsedata["headers"];
1742
1743 foreach (string header in headerdata.Keys)
1744 response.AddHeader(header, (string)headerdata[header]);
1745 }
1746
1708 byte[] buffer; 1747 byte[] buffer;
1709 1748
1710 if (!(contentType.Contains("image") 1749 if (responseData != null)
1711 || contentType.Contains("x-shockwave-flash")
1712 || contentType.Contains("application/x-oar")
1713 || contentType.Contains("application/vnd.ll.mesh")))
1714 { 1750 {
1715 // Text 1751 buffer = responseData;
1716 buffer = Encoding.UTF8.GetBytes(responseString);
1717 } 1752 }
1718 else 1753 else
1719 { 1754 {
1720 // Binary! 1755 if (!(contentType.Contains("image")
1721 buffer = Convert.FromBase64String(responseString); 1756 || contentType.Contains("x-shockwave-flash")
1722 } 1757 || contentType.Contains("application/x-oar")
1758 || contentType.Contains("application/vnd.ll.mesh")))
1759 {
1760 // Text
1761 buffer = Encoding.UTF8.GetBytes(responseString);
1762 }
1763 else
1764 {
1765 // Binary!
1766 buffer = Convert.FromBase64String(responseString);
1767 }
1723 1768
1724 response.SendChunked = false; 1769 response.SendChunked = false;
1725 response.ContentLength64 = buffer.Length; 1770 response.ContentLength64 = buffer.Length;
1726 response.ContentEncoding = Encoding.UTF8; 1771 response.ContentEncoding = Encoding.UTF8;
1772 }
1727 1773
1728 return buffer; 1774 return buffer;
1729 } 1775 }
@@ -1804,8 +1850,8 @@ namespace OpenSim.Framework.Servers.HttpServer
1804 m_httpListener2.Start(64); 1850 m_httpListener2.Start(64);
1805 1851
1806 // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events 1852 // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events
1807 m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000); 1853// m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000);
1808 m_PollServiceManager.Start(); 1854 m_PollServiceManager = new PollServiceRequestManager(this, 4, 25000);
1809 HTTPDRunning = true; 1855 HTTPDRunning = true;
1810 1856
1811 //HttpListenerContext context; 1857 //HttpListenerContext context;
@@ -1839,7 +1885,9 @@ namespace OpenSim.Framework.Servers.HttpServer
1839 1885
1840 public void httpServerException(object source, Exception exception) 1886 public void httpServerException(object source, Exception exception)
1841 { 1887 {
1842 m_log.Error(String.Format("[BASE HTTP SERVER]: {0} had an exception: {1} ", source.ToString(), exception.Message), exception); 1888 if (source.ToString() == "HttpServer.HttpListener" && exception.ToString().StartsWith("Mono.Security.Protocol.Tls.TlsException"))
1889 return;
1890 m_log.ErrorFormat("[BASE HTTP SERVER]: {0} had an exception {1}", source.ToString(), exception.ToString());
1843 /* 1891 /*
1844 if (HTTPDRunning)// && NotSocketErrors > 5) 1892 if (HTTPDRunning)// && NotSocketErrors > 5)
1845 { 1893 {
@@ -1856,7 +1904,7 @@ namespace OpenSim.Framework.Servers.HttpServer
1856 HTTPDRunning = false; 1904 HTTPDRunning = false;
1857 try 1905 try
1858 { 1906 {
1859 m_PollServiceManager.Stop(); 1907// m_PollServiceManager.Stop();
1860 1908
1861 m_httpListener2.ExceptionThrown -= httpServerException; 1909 m_httpListener2.ExceptionThrown -= httpServerException;
1862 //m_httpListener2.DisconnectHandler = null; 1910 //m_httpListener2.DisconnectHandler = null;
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
index 3089351..c19ac32 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
@@ -34,7 +34,7 @@ namespace OpenSim.Framework.Servers.HttpServer
34 public delegate void RequestMethod(UUID requestID, Hashtable request); 34 public delegate void RequestMethod(UUID requestID, Hashtable request);
35 public delegate bool HasEventsMethod(UUID requestID, UUID pId); 35 public delegate bool HasEventsMethod(UUID requestID, UUID pId);
36 36
37 public delegate Hashtable GetEventsMethod(UUID requestID, UUID pId, string request); 37 public delegate Hashtable GetEventsMethod(UUID requestID, UUID pId);
38 38
39 public delegate Hashtable NoEventsMethod(UUID requestID, UUID pId); 39 public delegate Hashtable NoEventsMethod(UUID requestID, UUID pId);
40 40
@@ -45,17 +45,30 @@ namespace OpenSim.Framework.Servers.HttpServer
45 public NoEventsMethod NoEvents; 45 public NoEventsMethod NoEvents;
46 public RequestMethod Request; 46 public RequestMethod Request;
47 public UUID Id; 47 public UUID Id;
48 public int TimeOutms;
49 public EventType Type;
50
51 public enum EventType : int
52 {
53 Normal = 0,
54 LslHttp = 1,
55 Inventory = 2,
56 Texture = 3,
57 Mesh = 4
58 }
48 59
49 public PollServiceEventArgs( 60 public PollServiceEventArgs(
50 RequestMethod pRequest, 61 RequestMethod pRequest,
51 HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents, 62 HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents,
52 UUID pId) 63 UUID pId, int pTimeOutms)
53 { 64 {
54 Request = pRequest; 65 Request = pRequest;
55 HasEvents = pHasEvents; 66 HasEvents = pHasEvents;
56 GetEvents = pGetEvents; 67 GetEvents = pGetEvents;
57 NoEvents = pNoEvents; 68 NoEvents = pNoEvents;
58 Id = pId; 69 Id = pId;
70 TimeOutms = pTimeOutms;
71 Type = EventType.Normal;
59 } 72 }
60 } 73 }
61} \ No newline at end of file 74}
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
index 3e84c55..5406f00 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
@@ -33,53 +33,54 @@ using log4net;
33using HttpServer; 33using HttpServer;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Framework.Monitoring; 35using OpenSim.Framework.Monitoring;
36using Amib.Threading;
37using System.IO;
38using System.Text;
39using System.Collections.Generic;
36 40
37namespace OpenSim.Framework.Servers.HttpServer 41namespace OpenSim.Framework.Servers.HttpServer
38{ 42{
39 public class PollServiceRequestManager 43 public class PollServiceRequestManager
40 { 44 {
41// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42 46
43 private readonly BaseHttpServer m_server; 47 private readonly BaseHttpServer m_server;
44 private static Queue m_requests = Queue.Synchronized(new Queue()); 48
49 private BlockingQueue<PollServiceHttpRequest> m_requests = new BlockingQueue<PollServiceHttpRequest>();
50 private static Queue<PollServiceHttpRequest> m_slowRequests = new Queue<PollServiceHttpRequest>();
51 private static Queue<PollServiceHttpRequest> m_retryRequests = new Queue<PollServiceHttpRequest>();
52
45 private uint m_WorkerThreadCount = 0; 53 private uint m_WorkerThreadCount = 0;
46 private Thread[] m_workerThreads; 54 private Thread[] m_workerThreads;
47 private PollServiceWorkerThread[] m_PollServiceWorkerThreads; 55 private Thread m_retrysThread;
48 private volatile bool m_running = true; 56
49 private int m_pollTimeout; 57 private bool m_running = true;
58 private int slowCount = 0;
59
60 private SmartThreadPool m_threadPool = new SmartThreadPool(20000, 12, 2);
50 61
51 public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout) 62 public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout)
52 { 63 {
53 m_server = pSrv; 64 m_server = pSrv;
54 m_WorkerThreadCount = pWorkerThreadCount; 65 m_WorkerThreadCount = pWorkerThreadCount;
55 m_pollTimeout = pTimeout;
56 }
57
58 public void Start()
59 {
60 m_running = true;
61 m_workerThreads = new Thread[m_WorkerThreadCount]; 66 m_workerThreads = new Thread[m_WorkerThreadCount];
62 m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount];
63 67
64 //startup worker threads 68 //startup worker threads
65 for (uint i = 0; i < m_WorkerThreadCount; i++) 69 for (uint i = 0; i < m_WorkerThreadCount; i++)
66 { 70 {
67 m_PollServiceWorkerThreads[i] = new PollServiceWorkerThread(m_server, m_pollTimeout);
68 m_PollServiceWorkerThreads[i].ReQueue += ReQueueEvent;
69
70 m_workerThreads[i] 71 m_workerThreads[i]
71 = Watchdog.StartThread( 72 = Watchdog.StartThread(
72 m_PollServiceWorkerThreads[i].ThreadStart, 73 PoolWorkerJob,
73 String.Format("PollServiceWorkerThread{0}", i), 74 String.Format("PollServiceWorkerThread{0}", i),
74 ThreadPriority.Normal, 75 ThreadPriority.Normal,
75 false, 76 false,
76 true, 77 false,
77 null, 78 null,
78 int.MaxValue); 79 int.MaxValue);
79 } 80 }
80 81
81 Watchdog.StartThread( 82 m_retrysThread = Watchdog.StartThread(
82 this.ThreadStart, 83 this.CheckRetries,
83 "PollServiceWatcherThread", 84 "PollServiceWatcherThread",
84 ThreadPriority.Normal, 85 ThreadPriority.Normal,
85 false, 86 false,
@@ -88,78 +89,206 @@ namespace OpenSim.Framework.Servers.HttpServer
88 1000 * 60 * 10); 89 1000 * 60 * 10);
89 } 90 }
90 91
91 internal void ReQueueEvent(PollServiceHttpRequest req) 92
93 private void ReQueueEvent(PollServiceHttpRequest req)
92 { 94 {
93 // Do accounting stuff here 95 if (m_running)
94 Enqueue(req); 96 {
97 lock (m_retryRequests)
98 m_retryRequests.Enqueue(req);
99 }
95 } 100 }
96 101
97 public void Enqueue(PollServiceHttpRequest req) 102 public void Enqueue(PollServiceHttpRequest req)
98 { 103 {
99 lock (m_requests) 104 if (m_running)
100 m_requests.Enqueue(req); 105 {
106 if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.Normal)
107 {
108 m_requests.Enqueue(req);
109 }
110 else
111 {
112 lock (m_slowRequests)
113 m_slowRequests.Enqueue(req);
114 }
115 }
101 } 116 }
102 117
103 public void ThreadStart() 118 private void CheckRetries()
104 { 119 {
105 while (m_running) 120 while (m_running)
106 { 121 {
122 Thread.Sleep(100); // let the world move .. back to faster rate
107 Watchdog.UpdateThread(); 123 Watchdog.UpdateThread();
108 ProcessQueuedRequests(); 124 lock (m_retryRequests)
109 Thread.Sleep(1000); 125 {
126 while (m_retryRequests.Count > 0 && m_running)
127 m_requests.Enqueue(m_retryRequests.Dequeue());
128 }
129 slowCount++;
130 if (slowCount >= 10)
131 {
132 slowCount = 0;
133
134 lock (m_slowRequests)
135 {
136 while (m_slowRequests.Count > 0 && m_running)
137 m_requests.Enqueue(m_slowRequests.Dequeue());
138 }
139 }
110 } 140 }
111 } 141 }
112 142
113 private void ProcessQueuedRequests() 143 ~PollServiceRequestManager()
114 { 144 {
115 lock (m_requests) 145 m_running = false;
146 Thread.Sleep(1000); // let the world move
147
148 foreach (Thread t in m_workerThreads)
149 Watchdog.AbortThread(t.ManagedThreadId);
150
151 try
152 {
153 foreach (PollServiceHttpRequest req in m_retryRequests)
154 {
155 DoHTTPGruntWork(m_server,req,
156 req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
157 }
158 }
159 catch
160 {
161 }
162
163 PollServiceHttpRequest wreq;
164 m_retryRequests.Clear();
165
166 lock (m_slowRequests)
116 { 167 {
117 if (m_requests.Count == 0) 168 while (m_slowRequests.Count > 0 && m_running)
118 return; 169 m_requests.Enqueue(m_slowRequests.Dequeue());
170 }
171
172 while (m_requests.Count() > 0)
173 {
174 try
175 {
176 wreq = m_requests.Dequeue(0);
177 DoHTTPGruntWork(m_server,wreq,
178 wreq.PollServiceArgs.NoEvents(wreq.RequestID, wreq.PollServiceArgs.Id));
179 }
180 catch
181 {
182 }
183 }
119 184
120// m_log.DebugFormat("[POLL SERVICE REQUEST MANAGER]: Processing {0} requests", m_requests.Count); 185 m_requests.Clear();
186 }
121 187
122 int reqperthread = (int) (m_requests.Count/m_WorkerThreadCount) + 1; 188 // work threads
123 189
124 // For Each WorkerThread 190 private void PoolWorkerJob()
125 for (int tc = 0; tc < m_WorkerThreadCount && m_requests.Count > 0; tc++) 191 {
192 while (m_running)
193 {
194 PollServiceHttpRequest req = m_requests.Dequeue(5000);
195
196 Watchdog.UpdateThread();
197 if (req != null)
126 { 198 {
127 //Loop over number of requests each thread handles. 199 try
128 for (int i = 0; i < reqperthread && m_requests.Count > 0; i++)
129 { 200 {
130 try 201 if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id))
131 { 202 {
132 m_PollServiceWorkerThreads[tc].Enqueue((PollServiceHttpRequest)m_requests.Dequeue()); 203 Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id);
204
205 if (responsedata == null)
206 continue;
207
208 if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.Normal) // This is the event queue
209 {
210 try
211 {
212 DoHTTPGruntWork(m_server, req, responsedata);
213 }
214 catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream
215 {
216 // Ignore it, no need to reply
217 }
218 }
219 else
220 {
221 m_threadPool.QueueWorkItem(x =>
222 {
223 try
224 {
225 DoHTTPGruntWork(m_server, req, responsedata);
226 }
227 catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream
228 {
229 // Ignore it, no need to reply
230 }
231
232 return null;
233 }, null);
234 }
133 } 235 }
134 catch (InvalidOperationException) 236 else
135 { 237 {
136 // The queue is empty, we did our calculations wrong! 238 if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms)
137 return; 239 {
240 DoHTTPGruntWork(m_server, req,
241 req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
242 }
243 else
244 {
245 ReQueueEvent(req);
246 }
138 } 247 }
139 248 }
249 catch (Exception e)
250 {
251 m_log.ErrorFormat("Exception in poll service thread: " + e.ToString());
140 } 252 }
141 } 253 }
142 } 254 }
143
144 } 255 }
145 256
146 public void Stop() 257 // DoHTTPGruntWork changed, not sending response
258 // do the same work around as core
259
260 internal static void DoHTTPGruntWork(BaseHttpServer server, PollServiceHttpRequest req, Hashtable responsedata)
147 { 261 {
148 m_running = false; 262 OSHttpResponse response
263 = new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request), req.HttpContext);
149 264
150 foreach (object o in m_requests) 265 byte[] buffer = server.DoHTTPGruntWork(responsedata, response);
151 {
152 PollServiceHttpRequest req = (PollServiceHttpRequest) o;
153 PollServiceWorkerThread.DoHTTPGruntWork(
154 m_server, req, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
155 }
156 266
157 m_requests.Clear(); 267 response.SendChunked = false;
268 response.ContentLength64 = buffer.Length;
269 response.ContentEncoding = Encoding.UTF8;
158 270
159 foreach (Thread t in m_workerThreads) 271 try
160 { 272 {
161 t.Abort(); 273 response.OutputStream.Write(buffer, 0, buffer.Length);
274 }
275 catch (Exception ex)
276 {
277 m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex));
278 }
279 finally
280 {
281 try
282 {
283 response.OutputStream.Flush();
284 response.Send();
285 }
286 catch (Exception e)
287 {
288 m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e));
289 }
162 } 290 }
163 } 291 }
164 } 292 }
165} \ No newline at end of file 293}
294
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs
deleted file mode 100644
index 5adbcd1..0000000
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs
+++ /dev/null
@@ -1,165 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.IO;
32using System.Text;
33using HttpServer;
34using OpenMetaverse;
35using System.Reflection;
36using log4net;
37using OpenSim.Framework.Monitoring;
38
39namespace OpenSim.Framework.Servers.HttpServer
40{
41 public delegate void ReQueuePollServiceItem(PollServiceHttpRequest req);
42
43 public class PollServiceWorkerThread
44 {
45 private static readonly ILog m_log =
46 LogManager.GetLogger(
47 MethodBase.GetCurrentMethod().DeclaringType);
48
49 public event ReQueuePollServiceItem ReQueue;
50
51 private readonly BaseHttpServer m_server;
52 private BlockingQueue<PollServiceHttpRequest> m_request;
53 private bool m_running = true;
54 private int m_timeout = 250;
55
56 public PollServiceWorkerThread(BaseHttpServer pSrv, int pTimeout)
57 {
58 m_request = new BlockingQueue<PollServiceHttpRequest>();
59 m_server = pSrv;
60 m_timeout = pTimeout;
61 }
62
63 public void ThreadStart()
64 {
65 Run();
66 }
67
68 public void Run()
69 {
70 while (m_running)
71 {
72 PollServiceHttpRequest req = m_request.Dequeue();
73
74 Watchdog.UpdateThread();
75
76 try
77 {
78 if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id))
79 {
80 StreamReader str;
81 try
82 {
83 str = new StreamReader(req.Request.Body);
84 }
85 catch (System.ArgumentException)
86 {
87 // Stream was not readable means a child agent
88 // was closed due to logout, leaving the
89 // Event Queue request orphaned.
90 continue;
91 }
92
93 Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id, str.ReadToEnd());
94 DoHTTPGruntWork(m_server, req, responsedata);
95 }
96 else
97 {
98 if ((Environment.TickCount - req.RequestTime) > m_timeout)
99 {
100 DoHTTPGruntWork(
101 m_server,
102 req,
103 req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
104 }
105 else
106 {
107 ReQueuePollServiceItem reQueueItem = ReQueue;
108 if (reQueueItem != null)
109 reQueueItem(req);
110 }
111 }
112 }
113 catch (Exception e)
114 {
115 m_log.ErrorFormat("Exception in poll service thread: " + e.ToString());
116 }
117 }
118 }
119
120 internal void Enqueue(PollServiceHttpRequest pPollServiceHttpRequest)
121 {
122 m_request.Enqueue(pPollServiceHttpRequest);
123 }
124
125 /// <summary>
126 /// FIXME: This should be part of BaseHttpServer
127 /// </summary>
128 internal static void DoHTTPGruntWork(BaseHttpServer server, PollServiceHttpRequest req, Hashtable responsedata)
129 {
130 OSHttpResponse response
131 = new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request), req.HttpContext);
132
133 byte[] buffer = server.DoHTTPGruntWork(responsedata, response);
134
135 response.SendChunked = false;
136 response.ContentLength64 = buffer.Length;
137 response.ContentEncoding = Encoding.UTF8;
138
139 try
140 {
141 response.OutputStream.Write(buffer, 0, buffer.Length);
142 }
143 catch (Exception ex)
144 {
145 m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex));
146 }
147 finally
148 {
149 //response.OutputStream.Close();
150 try
151 {
152 response.OutputStream.Flush();
153 response.Send();
154
155 //if (!response.KeepAlive && response.ReuseContext)
156 // response.FreeContext();
157 }
158 catch (Exception e)
159 {
160 m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e));
161 }
162 }
163 }
164 }
165} \ No newline at end of file