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.cs116
-rw-r--r--OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs6
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs4
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs60
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs361
5 files changed, 342 insertions, 205 deletions
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index f252bd5..cd14212 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -403,6 +403,7 @@ namespace OpenSim.Framework.Servers.HttpServer
403 StreamReader reader = new StreamReader(requestStream, encoding); 403 StreamReader reader = new StreamReader(requestStream, encoding);
404 404
405 string requestBody = reader.ReadToEnd(); 405 string requestBody = reader.ReadToEnd();
406 reader.Close();
406 407
407 Hashtable keysvals = new Hashtable(); 408 Hashtable keysvals = new Hashtable();
408 Hashtable headervals = new Hashtable(); 409 Hashtable headervals = new Hashtable();
@@ -460,7 +461,7 @@ namespace OpenSim.Framework.Servers.HttpServer
460 } 461 }
461 462
462 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); 463 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context);
463 resp.ReuseContext = true; 464 resp.ReuseContext = false;
464 HandleRequest(req, resp); 465 HandleRequest(req, resp);
465 466
466 // !!!HACK ALERT!!! 467 // !!!HACK ALERT!!!
@@ -759,7 +760,7 @@ namespace OpenSim.Framework.Servers.HttpServer
759 // Every month or so this will wrap and give bad numbers, not really a problem 760 // Every month or so this will wrap and give bad numbers, not really a problem
760 // since its just for reporting 761 // since its just for reporting
761 int tickdiff = requestEndTick - requestStartTick; 762 int tickdiff = requestEndTick - requestStartTick;
762 if (tickdiff > 3000 && requestHandler != null && requestHandler.Name != "GetTexture") 763 if (tickdiff > 3000 && (requestHandler == null || requestHandler.Name == null || requestHandler.Name != "GetTexture"))
763 { 764 {
764 m_log.InfoFormat( 765 m_log.InfoFormat(
765 "[LOGHTTP] Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms", 766 "[LOGHTTP] Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms",
@@ -1024,6 +1025,19 @@ namespace OpenSim.Framework.Servers.HttpServer
1024 string responseString = String.Empty; 1025 string responseString = String.Empty;
1025 XmlRpcRequest xmlRprcRequest = null; 1026 XmlRpcRequest xmlRprcRequest = null;
1026 1027
1028 bool gridproxy = false;
1029 if (requestBody.Contains("encoding=\"utf-8"))
1030 {
1031 int channelindx = -1;
1032 int optionsindx = requestBody.IndexOf(">options<");
1033 if(optionsindx >0)
1034 {
1035 channelindx = requestBody.IndexOf(">channel<");
1036 if (optionsindx < channelindx)
1037 gridproxy = true;
1038 }
1039 }
1040
1027 try 1041 try
1028 { 1042 {
1029 xmlRprcRequest = (XmlRpcRequest) (new XmlRpcRequestDeserializer()).Deserialize(requestBody); 1043 xmlRprcRequest = (XmlRpcRequest) (new XmlRpcRequestDeserializer()).Deserialize(requestBody);
@@ -1081,6 +1095,8 @@ namespace OpenSim.Framework.Servers.HttpServer
1081 } 1095 }
1082 xmlRprcRequest.Params.Add(request.Headers.Get(xff)); // Param[3] 1096 xmlRprcRequest.Params.Add(request.Headers.Get(xff)); // Param[3]
1083 1097
1098 if (gridproxy)
1099 xmlRprcRequest.Params.Add("gridproxy"); // Param[4]
1084 try 1100 try
1085 { 1101 {
1086 xmlRpcResponse = method(xmlRprcRequest, request.RemoteIPEndPoint); 1102 xmlRpcResponse = method(xmlRprcRequest, request.RemoteIPEndPoint);
@@ -1254,7 +1270,8 @@ namespace OpenSim.Framework.Servers.HttpServer
1254 requestStream.Close(); 1270 requestStream.Close();
1255 1271
1256 //m_log.DebugFormat("[OGP]: {0}:{1}", request.RawUrl, requestBody); 1272 //m_log.DebugFormat("[OGP]: {0}:{1}", request.RawUrl, requestBody);
1257 response.KeepAlive = true; 1273 // response.KeepAlive = true;
1274 response.KeepAlive = false;
1258 1275
1259 OSD llsdRequest = null; 1276 OSD llsdRequest = null;
1260 OSD llsdResponse = null; 1277 OSD llsdResponse = null;
@@ -1732,10 +1749,40 @@ namespace OpenSim.Framework.Servers.HttpServer
1732 1749
1733 internal byte[] DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response) 1750 internal byte[] DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response)
1734 { 1751 {
1735 //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response"); 1752 int responsecode;
1736 int responsecode = (int)responsedata["int_response_code"]; 1753 string responseString = String.Empty;
1737 string responseString = (string)responsedata["str_response_string"]; 1754 byte[] responseData = null;
1738 string contentType = (string)responsedata["content_type"]; 1755 string contentType;
1756
1757 if (responsedata == null)
1758 {
1759 responsecode = 500;
1760 responseString = "No response could be obtained";
1761 contentType = "text/plain";
1762 responsedata = new Hashtable();
1763 }
1764 else
1765 {
1766 try
1767 {
1768 //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response");
1769 responsecode = (int)responsedata["int_response_code"];
1770 if (responsedata["bin_response_data"] != null)
1771 responseData = (byte[])responsedata["bin_response_data"];
1772 else
1773 responseString = (string)responsedata["str_response_string"];
1774 contentType = (string)responsedata["content_type"];
1775 if (responseString == null)
1776 responseString = String.Empty;
1777 }
1778 catch
1779 {
1780 responsecode = 500;
1781 responseString = "No response could be obtained";
1782 contentType = "text/plain";
1783 responsedata = new Hashtable();
1784 }
1785 }
1739 1786
1740 if (responsedata.ContainsKey("error_status_text")) 1787 if (responsedata.ContainsKey("error_status_text"))
1741 { 1788 {
@@ -1745,16 +1792,19 @@ namespace OpenSim.Framework.Servers.HttpServer
1745 { 1792 {
1746 response.ProtocolVersion = (string)responsedata["http_protocol_version"]; 1793 response.ProtocolVersion = (string)responsedata["http_protocol_version"];
1747 } 1794 }
1748 1795/*
1749 if (responsedata.ContainsKey("keepalive")) 1796 if (responsedata.ContainsKey("keepalive"))
1750 { 1797 {
1751 bool keepalive = (bool)responsedata["keepalive"]; 1798 bool keepalive = (bool)responsedata["keepalive"];
1752 response.KeepAlive = keepalive; 1799 response.KeepAlive = keepalive;
1753
1754 } 1800 }
1755 1801
1756 if (responsedata.ContainsKey("reusecontext")) 1802 if (responsedata.ContainsKey("reusecontext"))
1757 response.ReuseContext = (bool) responsedata["reusecontext"]; 1803 response.ReuseContext = (bool) responsedata["reusecontext"];
1804*/
1805 // disable this things
1806 response.KeepAlive = false;
1807 response.ReuseContext = false;
1758 1808
1759 // Cross-Origin Resource Sharing with simple requests 1809 // Cross-Origin Resource Sharing with simple requests
1760 if (responsedata.ContainsKey("access_control_allow_origin")) 1810 if (responsedata.ContainsKey("access_control_allow_origin"))
@@ -1768,8 +1818,11 @@ namespace OpenSim.Framework.Servers.HttpServer
1768 contentType = "text/html"; 1818 contentType = "text/html";
1769 } 1819 }
1770 1820
1821
1822
1771 // The client ignores anything but 200 here for web login, so ensure that this is 200 for that 1823 // The client ignores anything but 200 here for web login, so ensure that this is 200 for that
1772 1824
1825
1773 response.StatusCode = responsecode; 1826 response.StatusCode = responsecode;
1774 1827
1775 if (responsecode == (int)OSHttpStatusCode.RedirectMovedPermanently) 1828 if (responsecode == (int)OSHttpStatusCode.RedirectMovedPermanently)
@@ -1780,25 +1833,40 @@ namespace OpenSim.Framework.Servers.HttpServer
1780 1833
1781 response.AddHeader("Content-Type", contentType); 1834 response.AddHeader("Content-Type", contentType);
1782 1835
1836 if (responsedata.ContainsKey("headers"))
1837 {
1838 Hashtable headerdata = (Hashtable)responsedata["headers"];
1839
1840 foreach (string header in headerdata.Keys)
1841 response.AddHeader(header, (string)headerdata[header]);
1842 }
1843
1783 byte[] buffer; 1844 byte[] buffer;
1784 1845
1785 if (!(contentType.Contains("image") 1846 if (responseData != null)
1786 || contentType.Contains("x-shockwave-flash")
1787 || contentType.Contains("application/x-oar")
1788 || contentType.Contains("application/vnd.ll.mesh")))
1789 { 1847 {
1790 // Text 1848 buffer = responseData;
1791 buffer = Encoding.UTF8.GetBytes(responseString);
1792 } 1849 }
1793 else 1850 else
1794 { 1851 {
1795 // Binary! 1852 if (!(contentType.Contains("image")
1796 buffer = Convert.FromBase64String(responseString); 1853 || contentType.Contains("x-shockwave-flash")
1797 } 1854 || contentType.Contains("application/x-oar")
1855 || contentType.Contains("application/vnd.ll.mesh")))
1856 {
1857 // Text
1858 buffer = Encoding.UTF8.GetBytes(responseString);
1859 }
1860 else
1861 {
1862 // Binary!
1863 buffer = Convert.FromBase64String(responseString);
1864 }
1798 1865
1799 response.SendChunked = false; 1866 response.SendChunked = false;
1800 response.ContentLength64 = buffer.Length; 1867 response.ContentLength64 = buffer.Length;
1801 response.ContentEncoding = Encoding.UTF8; 1868 response.ContentEncoding = Encoding.UTF8;
1869 }
1802 1870
1803 return buffer; 1871 return buffer;
1804 } 1872 }
@@ -1886,6 +1954,7 @@ namespace OpenSim.Framework.Servers.HttpServer
1886 m_httpListener2.Start(64); 1954 m_httpListener2.Start(64);
1887 1955
1888 // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events 1956 // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events
1957
1889 PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 3, 25000); 1958 PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 3, 25000);
1890 PollServiceRequestManager.Start(); 1959 PollServiceRequestManager.Start();
1891 1960
@@ -1937,7 +2006,9 @@ namespace OpenSim.Framework.Servers.HttpServer
1937 2006
1938 public void httpServerException(object source, Exception exception) 2007 public void httpServerException(object source, Exception exception)
1939 { 2008 {
1940 m_log.Error(String.Format("[BASE HTTP SERVER]: {0} had an exception: {1} ", source.ToString(), exception.Message), exception); 2009 if (source.ToString() == "HttpServer.HttpListener" && exception.ToString().StartsWith("Mono.Security.Protocol.Tls.TlsException"))
2010 return;
2011 m_log.ErrorFormat("[BASE HTTP SERVER]: {0} had an exception {1}", source.ToString(), exception.ToString());
1941 /* 2012 /*
1942 if (HTTPDRunning)// && NotSocketErrors > 5) 2013 if (HTTPDRunning)// && NotSocketErrors > 5)
1943 { 2014 {
@@ -1984,6 +2055,7 @@ namespace OpenSim.Framework.Servers.HttpServer
1984 2055
1985 public void RemoveHTTPHandler(string httpMethod, string path) 2056 public void RemoveHTTPHandler(string httpMethod, string path)
1986 { 2057 {
2058 if (path == null) return; // Caps module isn't loaded, tries to remove handler where path = null
1987 lock (m_HTTPHandlers) 2059 lock (m_HTTPHandlers)
1988 { 2060 {
1989 if (httpMethod != null && httpMethod.Length == 0) 2061 if (httpMethod != null && httpMethod.Length == 0)
diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs
index 89fb5d4..17e9dc2 100644
--- a/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs
+++ b/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs
@@ -148,6 +148,7 @@ namespace OpenSim.Framework.Servers.HttpServer
148 _httpResponse.Connection = ConnectionType.Close; 148 _httpResponse.Connection = ConnectionType.Close;
149 _httpResponse.KeepAlive = 0; 149 _httpResponse.KeepAlive = 0;
150 } 150 }
151
151 else 152 else
152 { 153 {
153 _httpResponse.Connection = ConnectionType.KeepAlive; 154 _httpResponse.Connection = ConnectionType.KeepAlive;
@@ -320,6 +321,11 @@ namespace OpenSim.Framework.Servers.HttpServer
320 public void Send() 321 public void Send()
321 { 322 {
322 _httpResponse.Body.Flush(); 323 _httpResponse.Body.Flush();
324
325 // disable this till they are safe to use
326 _httpResponse.Connection = ConnectionType.Close;
327 _httpResponse.Chunked = false;
328
323 _httpResponse.Send(); 329 _httpResponse.Send();
324 } 330 }
325 331
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
index 9477100..3fd3bf7 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
@@ -52,7 +52,9 @@ namespace OpenSim.Framework.Servers.HttpServer
52 { 52 {
53 LongPoll = 0, 53 LongPoll = 0,
54 LslHttp = 1, 54 LslHttp = 1,
55 Inventory = 2 55 Inventory = 2,
56 Texture = 3,
57 Mesh = 4
56 } 58 }
57 59
58 public string Url { get; set; } 60 public string Url { get; set; }
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs
index caf0e98..49cd110 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using System.Reflection; 31using System.Reflection;
31using System.Text; 32using System.Text;
32using HttpServer; 33using HttpServer;
@@ -44,6 +45,24 @@ namespace OpenSim.Framework.Servers.HttpServer
44 public readonly IHttpRequest Request; 45 public readonly IHttpRequest Request;
45 public readonly int RequestTime; 46 public readonly int RequestTime;
46 public readonly UUID RequestID; 47 public readonly UUID RequestID;
48 public int contextHash;
49
50 private void GenContextHash()
51 {
52 Random rnd = new Random();
53 contextHash = 0;
54 if (Request.Headers["remote_addr"] != null)
55 contextHash = (Request.Headers["remote_addr"]).GetHashCode() << 16;
56 else
57 contextHash = rnd.Next() << 16;
58 if (Request.Headers["remote_port"] != null)
59 {
60 string[] strPorts = Request.Headers["remote_port"].Split(new char[] { ',' });
61 contextHash += Int32.Parse(strPorts[0]);
62 }
63 else
64 contextHash += rnd.Next() & 0xffff;
65 }
47 66
48 public PollServiceHttpRequest( 67 public PollServiceHttpRequest(
49 PollServiceEventArgs pPollServiceArgs, IHttpClientContext pHttpContext, IHttpRequest pRequest) 68 PollServiceEventArgs pPollServiceArgs, IHttpClientContext pHttpContext, IHttpRequest pRequest)
@@ -53,6 +72,7 @@ namespace OpenSim.Framework.Servers.HttpServer
53 Request = pRequest; 72 Request = pRequest;
54 RequestTime = System.Environment.TickCount; 73 RequestTime = System.Environment.TickCount;
55 RequestID = UUID.Random(); 74 RequestID = UUID.Random();
75 GenContextHash();
56 } 76 }
57 77
58 internal void DoHTTPGruntWork(BaseHttpServer server, Hashtable responsedata) 78 internal void DoHTTPGruntWork(BaseHttpServer server, Hashtable responsedata)
@@ -65,6 +85,7 @@ namespace OpenSim.Framework.Servers.HttpServer
65 response.SendChunked = false; 85 response.SendChunked = false;
66 response.ContentLength64 = buffer.Length; 86 response.ContentLength64 = buffer.Length;
67 response.ContentEncoding = Encoding.UTF8; 87 response.ContentEncoding = Encoding.UTF8;
88 response.ReuseContext = false;
68 89
69 try 90 try
70 { 91 {
@@ -93,5 +114,44 @@ namespace OpenSim.Framework.Servers.HttpServer
93 PollServiceArgs.RequestsHandled++; 114 PollServiceArgs.RequestsHandled++;
94 } 115 }
95 } 116 }
117
118 internal void DoHTTPstop(BaseHttpServer server)
119 {
120 OSHttpResponse response
121 = new OSHttpResponse(new HttpResponse(HttpContext, Request), HttpContext);
122
123 response.SendChunked = false;
124 response.ContentLength64 = 0;
125 response.ContentEncoding = Encoding.UTF8;
126 response.ReuseContext = false;
127 response.KeepAlive = false;
128 response.SendChunked = false;
129 response.StatusCode = 503;
130
131 try
132 {
133 response.OutputStream.Flush();
134 response.Send();
135 }
136 catch (Exception e)
137 {
138 }
139 }
140 }
141
142 class PollServiceHttpRequestComparer : IEqualityComparer<PollServiceHttpRequest>
143 {
144 public bool Equals(PollServiceHttpRequest b1, PollServiceHttpRequest b2)
145 {
146 if (b1.contextHash != b2.contextHash)
147 return false;
148 bool b = Object.ReferenceEquals(b1.HttpContext, b2.HttpContext);
149 return b;
150 }
151
152 public int GetHashCode(PollServiceHttpRequest b2)
153 {
154 return (int)b2.contextHash;
155 }
96 } 156 }
97} \ No newline at end of file 157} \ No newline at end of file
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
index 28bba70..0e4323a 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
@@ -44,183 +44,199 @@ namespace OpenSim.Framework.Servers.HttpServer
44 { 44 {
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 46
47 /// <summary>
48 /// Is the poll service request manager running?
49 /// </summary>
50 /// <remarks>
51 /// Can be running either synchronously or asynchronously
52 /// </remarks>
53 public bool IsRunning { get; private set; }
54
55 /// <summary>
56 /// Is the poll service performing responses asynchronously (with its own threads) or synchronously (via
57 /// external calls)?
58 /// </summary>
59 public bool PerformResponsesAsync { get; private set; }
60
61 /// <summary>
62 /// Number of responses actually processed and sent to viewer (or aborted due to error).
63 /// </summary>
64 public int ResponsesProcessed { get; private set; }
65
66 private readonly BaseHttpServer m_server; 47 private readonly BaseHttpServer m_server;
67 48
49 private Dictionary<PollServiceHttpRequest, Queue<PollServiceHttpRequest>> m_bycontext;
68 private BlockingQueue<PollServiceHttpRequest> m_requests = new BlockingQueue<PollServiceHttpRequest>(); 50 private BlockingQueue<PollServiceHttpRequest> m_requests = new BlockingQueue<PollServiceHttpRequest>();
69 private static List<PollServiceHttpRequest> m_longPollRequests = new List<PollServiceHttpRequest>(); 51 private static Queue<PollServiceHttpRequest> m_slowRequests = new Queue<PollServiceHttpRequest>();
52 private static Queue<PollServiceHttpRequest> m_retryRequests = new Queue<PollServiceHttpRequest>();
70 53
71 private uint m_WorkerThreadCount = 0; 54 private uint m_WorkerThreadCount = 0;
72 private Thread[] m_workerThreads; 55 private Thread[] m_workerThreads;
56 private Thread m_retrysThread;
57
58 private bool m_running = false;
59 private int slowCount = 0;
73 60
74 private SmartThreadPool m_threadPool = new SmartThreadPool(20000, 12, 2); 61 private SmartThreadPool m_threadPool;
75 62
76// private int m_timeout = 1000; // increase timeout 250; now use the event one
77 63
78 public PollServiceRequestManager( 64 public PollServiceRequestManager(
79 BaseHttpServer pSrv, bool performResponsesAsync, uint pWorkerThreadCount, int pTimeout) 65 BaseHttpServer pSrv, bool performResponsesAsync, uint pWorkerThreadCount, int pTimeout)
80 { 66 {
81 m_server = pSrv; 67 m_server = pSrv;
82 PerformResponsesAsync = performResponsesAsync;
83 m_WorkerThreadCount = pWorkerThreadCount; 68 m_WorkerThreadCount = pWorkerThreadCount;
84 m_workerThreads = new Thread[m_WorkerThreadCount]; 69 m_workerThreads = new Thread[m_WorkerThreadCount];
85 70
86 StatsManager.RegisterStat( 71 PollServiceHttpRequestComparer preqCp = new PollServiceHttpRequestComparer();
87 new Stat( 72 m_bycontext = new Dictionary<PollServiceHttpRequest, Queue<PollServiceHttpRequest>>(preqCp);
88 "QueuedPollResponses", 73
89 "Number of poll responses queued for processing.", 74 STPStartInfo startInfo = new STPStartInfo();
90 "", 75 startInfo.IdleTimeout = 30000;
91 "", 76 startInfo.MaxWorkerThreads = 15;
92 "httpserver", 77 startInfo.MinWorkerThreads = 1;
93 m_server.Port.ToString(), 78 startInfo.ThreadPriority = ThreadPriority.Normal;
94 StatType.Pull, 79 startInfo.StartSuspended = true;
95 MeasuresOfInterest.AverageChangeOverTime, 80 startInfo.ThreadPoolName = "PoolService";
96 stat => stat.Value = m_requests.Count(), 81
97 StatVerbosity.Debug)); 82 m_threadPool = new SmartThreadPool(startInfo);
98 83
99 StatsManager.RegisterStat(
100 new Stat(
101 "ProcessedPollResponses",
102 "Number of poll responses processed.",
103 "",
104 "",
105 "httpserver",
106 m_server.Port.ToString(),
107 StatType.Pull,
108 MeasuresOfInterest.AverageChangeOverTime,
109 stat => stat.Value = ResponsesProcessed,
110 StatVerbosity.Debug));
111 } 84 }
112 85
113 public void Start() 86 public void Start()
114 { 87 {
115 IsRunning = true; 88 m_running = true;
116 89 m_threadPool.Start();
117 if (PerformResponsesAsync) 90 //startup worker threads
91 for (uint i = 0; i < m_WorkerThreadCount; i++)
118 { 92 {
119 //startup worker threads 93 m_workerThreads[i]
120 for (uint i = 0; i < m_WorkerThreadCount; i++) 94 = WorkManager.StartThread(
121 { 95 PoolWorkerJob,
122 m_workerThreads[i] 96 string.Format("PollServiceWorkerThread {0}:{1}", i, m_server.Port),
123 = WorkManager.StartThread( 97 ThreadPriority.Normal,
124 PoolWorkerJob, 98 false,
125 string.Format("PollServiceWorkerThread{0}:{1}", i, m_server.Port), 99 false,
126 ThreadPriority.Normal, 100 null,
127 false, 101 int.MaxValue);
128 false,
129 null,
130 int.MaxValue);
131 }
132
133 WorkManager.StartThread(
134 this.CheckLongPollThreads,
135 string.Format("LongPollServiceWatcherThread:{0}", m_server.Port),
136 ThreadPriority.Normal,
137 false,
138 true,
139 null,
140 1000 * 60 * 10);
141 } 102 }
103
104 m_retrysThread = WorkManager.StartThread(
105 this.CheckRetries,
106 string.Format("PollServiceWatcherThread:{0}", m_server.Port),
107 ThreadPriority.Normal,
108 false,
109 true,
110 null,
111 1000 * 60 * 10);
112
113
142 } 114 }
143 115
144 private void ReQueueEvent(PollServiceHttpRequest req) 116 private void ReQueueEvent(PollServiceHttpRequest req)
145 { 117 {
146 if (IsRunning) 118 if (m_running)
147 { 119 {
148 // delay the enqueueing for 100ms. There's no need to have the event 120 lock (m_retryRequests)
149 // actively on the queue 121 m_retryRequests.Enqueue(req);
150 Timer t = new Timer(self => {
151 ((Timer)self).Dispose();
152 m_requests.Enqueue(req);
153 });
154
155 t.Change(100, Timeout.Infinite);
156
157 } 122 }
158 } 123 }
159 124
160 public void Enqueue(PollServiceHttpRequest req) 125 public void Enqueue(PollServiceHttpRequest req)
161 { 126 {
162 if (IsRunning) 127 lock (m_bycontext)
163 { 128 {
164 if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) 129 Queue<PollServiceHttpRequest> ctxQeueue;
130 if (m_bycontext.TryGetValue(req, out ctxQeueue))
165 { 131 {
166 lock (m_longPollRequests) 132 ctxQeueue.Enqueue(req);
167 m_longPollRequests.Add(req);
168 } 133 }
169 else 134 else
170 m_requests.Enqueue(req); 135 {
136 ctxQeueue = new Queue<PollServiceHttpRequest>();
137 m_bycontext[req] = ctxQeueue;
138 EnqueueInt(req);
139 }
171 } 140 }
172 } 141 }
173 142
174 private void CheckLongPollThreads() 143 public void byContextDequeue(PollServiceHttpRequest req)
175 { 144 {
176 // The only purpose of this thread is to check the EQs for events. 145 Queue<PollServiceHttpRequest> ctxQeueue;
177 // If there are events, that thread will be placed in the "ready-to-serve" queue, m_requests. 146 lock (m_bycontext)
178 // If there are no events, that thread will be back to its "waiting" queue, m_longPollRequests.
179 // All other types of tasks (Inventory handlers, http-in, etc) don't have the long-poll nature,
180 // so if they aren't ready to be served by a worker thread (no events), they are placed
181 // directly back in the "ready-to-serve" queue by the worker thread.
182 while (IsRunning)
183 { 147 {
184 Thread.Sleep(500); 148 if (m_bycontext.TryGetValue(req, out ctxQeueue))
185 Watchdog.UpdateThread();
186
187// List<PollServiceHttpRequest> not_ready = new List<PollServiceHttpRequest>();
188 lock (m_longPollRequests)
189 { 149 {
190 if (m_longPollRequests.Count > 0 && IsRunning) 150 if (ctxQeueue.Count > 0)
191 { 151 {
192 List<PollServiceHttpRequest> ready = m_longPollRequests.FindAll(req => 152 PollServiceHttpRequest newreq = ctxQeueue.Dequeue();
193 (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ 153 EnqueueInt(newreq);
194 (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout 154 }
195 ); 155 else
156 {
157 m_bycontext.Remove(req);
158 }
159 }
160 }
161 }
196 162
197 ready.ForEach(req =>
198 {
199 m_requests.Enqueue(req);
200 m_longPollRequests.Remove(req);
201 });
202 163
203 } 164 public void EnqueueInt(PollServiceHttpRequest req)
165 {
166 if (m_running)
167 {
168 if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.LongPoll)
169 {
170 m_requests.Enqueue(req);
171 }
172 else
173 {
174 lock (m_slowRequests)
175 m_slowRequests.Enqueue(req);
176 }
177 }
178 }
179
180 private void CheckRetries()
181 {
182 while (m_running)
183
184 {
185 Thread.Sleep(100); // let the world move .. back to faster rate
186 Watchdog.UpdateThread();
187 lock (m_retryRequests)
188 {
189 while (m_retryRequests.Count > 0 && m_running)
190 m_requests.Enqueue(m_retryRequests.Dequeue());
191 }
192 slowCount++;
193 if (slowCount >= 10)
194 {
195 slowCount = 0;
204 196
197 lock (m_slowRequests)
198 {
199 while (m_slowRequests.Count > 0 && m_running)
200 m_requests.Enqueue(m_slowRequests.Dequeue());
201 }
205 } 202 }
206 } 203 }
207 } 204 }
208 205
209 public void Stop() 206 public void Stop()
210 { 207 {
211 IsRunning = false; 208 m_running = false;
212// m_timeout = -10000; // cause all to expire 209
213 Thread.Sleep(1000); // let the world move 210 Thread.Sleep(1000); // let the world move
214 211
215 foreach (Thread t in m_workerThreads) 212 foreach (Thread t in m_workerThreads)
216 Watchdog.AbortThread(t.ManagedThreadId); 213 Watchdog.AbortThread(t.ManagedThreadId);
217 214
215 // any entry in m_bycontext should have a active request on the other queues
216 // so just delete contents to easy GC
217 foreach (Queue<PollServiceHttpRequest> qu in m_bycontext.Values)
218 qu.Clear();
219 m_bycontext.Clear();
220
221 try
222 {
223 foreach (PollServiceHttpRequest req in m_retryRequests)
224 {
225 req.DoHTTPstop(m_server);
226 }
227 }
228 catch
229 {
230 }
231
218 PollServiceHttpRequest wreq; 232 PollServiceHttpRequest wreq;
233 m_retryRequests.Clear();
219 234
220 lock (m_longPollRequests) 235 lock (m_slowRequests)
221 { 236 {
222 if (m_longPollRequests.Count > 0 && IsRunning) 237 while (m_slowRequests.Count > 0)
223 m_longPollRequests.ForEach(req => m_requests.Enqueue(req)); 238 m_requests.Enqueue(m_slowRequests.Dequeue());
239
224 } 240 }
225 241
226 while (m_requests.Count() > 0) 242 while (m_requests.Count() > 0)
@@ -228,16 +244,14 @@ namespace OpenSim.Framework.Servers.HttpServer
228 try 244 try
229 { 245 {
230 wreq = m_requests.Dequeue(0); 246 wreq = m_requests.Dequeue(0);
231 ResponsesProcessed++; 247 wreq.DoHTTPstop(m_server);
232 wreq.DoHTTPGruntWork( 248
233 m_server, wreq.PollServiceArgs.NoEvents(wreq.RequestID, wreq.PollServiceArgs.Id));
234 } 249 }
235 catch 250 catch
236 { 251 {
237 } 252 }
238 } 253 }
239 254
240 m_longPollRequests.Clear();
241 m_requests.Clear(); 255 m_requests.Clear();
242 } 256 }
243 257
@@ -245,87 +259,70 @@ namespace OpenSim.Framework.Servers.HttpServer
245 259
246 private void PoolWorkerJob() 260 private void PoolWorkerJob()
247 { 261 {
248 while (IsRunning) 262 while (m_running)
249 { 263 {
250 Watchdog.UpdateThread(); 264 PollServiceHttpRequest req = m_requests.Dequeue(5000);
251 WaitPerformResponse();
252 }
253 }
254
255 public void WaitPerformResponse()
256 {
257 PollServiceHttpRequest req = m_requests.Dequeue(5000);
258// m_log.DebugFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString()));
259 265
260 if (req != null) 266 Watchdog.UpdateThread();
261 { 267 if (req != null)
262 try
263 { 268 {
264 if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) 269 try
265 { 270 {
266 Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id); 271 if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id))
267
268 if (responsedata == null)
269 return;
270
271 // This is the event queue.
272 // Even if we're not running we can still perform responses by explicit request.
273 if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll
274 || !PerformResponsesAsync)
275 { 272 {
276 try 273 Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id);
277 { 274
278 ResponsesProcessed++; 275 if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue
279 req.DoHTTPGruntWork(m_server, responsedata);
280 }
281 catch (ObjectDisposedException e) // Browser aborted before we could read body, server closed the stream
282 {
283 // Ignore it, no need to reply
284 m_log.Error(e);
285 }
286 }
287 else
288 {
289 m_threadPool.QueueWorkItem(x =>
290 { 276 {
291 try 277 try
292 { 278 {
293 ResponsesProcessed++;
294 req.DoHTTPGruntWork(m_server, responsedata); 279 req.DoHTTPGruntWork(m_server, responsedata);
280 byContextDequeue(req);
295 } 281 }
296 catch (ObjectDisposedException e) // Browser aborted before we could read body, server closed the stream 282 catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream
297 { 283 {
298 // Ignore it, no need to reply 284 // Ignore it, no need to reply
299 m_log.Error(e);
300 } 285 }
301 catch (Exception e) 286 }
287 else
288 {
289 m_threadPool.QueueWorkItem(x =>
302 { 290 {
303 m_log.Error(e); 291 try
304 } 292 {
305 293 req.DoHTTPGruntWork(m_server, responsedata);
306 return null; 294 byContextDequeue(req);
307 }, null); 295 }
308 } 296 catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream
309 } 297 {
310 else 298 // Ignore it, no need to reply
311 { 299 }
312 if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) 300
313 { 301 return null;
314 ResponsesProcessed++; 302 }, null);
315 req.DoHTTPGruntWork( 303 }
316 m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
317 } 304 }
318 else 305 else
319 { 306 {
320 ReQueueEvent(req); 307 if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms)
308 {
309 req.DoHTTPGruntWork(m_server,
310 req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
311 byContextDequeue(req);
312 }
313 else
314 {
315 ReQueueEvent(req);
316 }
321 } 317 }
322 } 318 }
323 } 319 catch (Exception e)
324 catch (Exception e) 320 {
325 { 321 m_log.ErrorFormat("Exception in poll service thread: " + e.ToString());
326 m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); 322 }
327 } 323 }
328 } 324 }
329 } 325 }
326
330 } 327 }
331} \ No newline at end of file 328}