From 5b5e53aa1d3e9eba7ec08d438464f4526d091887 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 3 Nov 2018 11:43:47 +0000 Subject: [PATCH] we should only have one http poll service manager per instance --- .../Servers/HttpServer/BaseHttpServer.cs | 112 ++++++++--------- .../HttpServer/PollServiceHttpRequest.cs | 118 +++++++++++++++++- .../HttpServer/PollServiceRequestManager.cs | 23 ++-- OpenSim/Framework/Servers/MainServer.cs | 9 +- 4 files changed, 182 insertions(+), 80 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 4c9b19da91..83cf90489a 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -44,11 +44,11 @@ using log4net; using Nwc.XmlRpc; using OpenMetaverse.StructuredData; using CoolHTTPListener = HttpServer.HttpListener; -using HttpListener = System.Net.HttpListener; using LogPrio = HttpServer.LogPrio; using OpenSim.Framework.Monitoring; using System.IO.Compression; using System.Security.Cryptography; +using OpenSim.Framework.Servers; namespace OpenSim.Framework.Servers.HttpServer { @@ -57,6 +57,8 @@ namespace OpenSim.Framework.Servers.HttpServer private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); private static Encoding UTF8NoBOM = new System.Text.UTF8Encoding(false); + public static PollServiceRequestManager m_pollServiceManager; + private static object m_generalLock = new object(); /// /// This is a pending websocket request before it got an sucessful upgrade response. @@ -119,7 +121,6 @@ namespace OpenSim.Framework.Servers.HttpServer protected IPAddress m_listenIPAddress = IPAddress.Any; - public PollServiceRequestManager PollServiceRequestManager { get; private set; } public string Protocol { @@ -249,46 +250,46 @@ namespace OpenSim.Framework.Servers.HttpServer m_ssl = false; } - static bool MatchDNS (string hostname, string dns) - { - int indx = dns.IndexOf ('*'); - if (indx == -1) - return (String.Compare(hostname, dns, true, CultureInfo.InvariantCulture) == 0); - + static bool MatchDNS(string hostname, string dns) + { + int indx = dns.IndexOf('*'); + if (indx == -1) + return (String.Compare(hostname, dns, true, CultureInfo.InvariantCulture) == 0); + int dnslen = dns.Length; dnslen--; - if(indx == dnslen) + if (indx == dnslen) return true; // just * ? - if(indx > dnslen - 2) + if (indx > dnslen - 2) return false; // 2 short ? - if (dns[indx + 1] != '.') - return false; - - int indx2 = dns.IndexOf ('*', indx + 1); - if (indx2 != -1) - return false; // there can only be one; - - string end = dns.Substring(indx + 1); + if (dns[indx + 1] != '.') + return false; + + int indx2 = dns.IndexOf('*', indx + 1); + if (indx2 != -1) + return false; // there can only be one; + + string end = dns.Substring(indx + 1); int hostlen = hostname.Length; int endlen = end.Length; - int length = hostlen - endlen; - if (length <= 0) - return false; + int length = hostlen - endlen; + if (length <= 0) + return false; - if (String.Compare(hostname, length, end, 0, endlen, true, CultureInfo.InvariantCulture) != 0) - return false; - - if (indx == 0) - { - indx2 = hostname.IndexOf ('.'); - return ((indx2 == -1) || (indx2 >= length)); - } - - string start = dns.Substring (0, indx); - return (String.Compare (hostname, 0, start, 0, start.Length, true, CultureInfo.InvariantCulture) == 0); - } + if (String.Compare(hostname, length, end, 0, endlen, true, CultureInfo.InvariantCulture) != 0) + return false; + + if (indx == 0) + { + indx2 = hostname.IndexOf('.'); + return ((indx2 == -1) || (indx2 >= length)); + } + + string start = dns.Substring(0, indx); + return (String.Compare(hostname, 0, start, 0, start.Length, true, CultureInfo.InvariantCulture) == 0); + } public bool CheckSSLCertHost(string hostname) { @@ -527,7 +528,6 @@ namespace OpenSim.Framework.Servers.HttpServer public void OnRequest(object source, RequestEventArgs args) { RequestNumber++; - try { IHttpClientContext context = (IHttpClientContext)source; @@ -576,7 +576,7 @@ namespace OpenSim.Framework.Servers.HttpServer psEvArgs.Request(psreq.RequestID, keysvals); } - PollServiceRequestManager.Enqueue(psreq); + m_pollServiceManager.Enqueue(psreq); } else { @@ -616,16 +616,6 @@ namespace OpenSim.Framework.Servers.HttpServer request.AcceptTypes[i] = string.Empty; } - // public void ConvertIHttpClientContextToOSHttp(object stateinfo) - // { - // HttpServerContextObj objstate = (HttpServerContextObj)stateinfo; - - // OSHttpRequest request = objstate.oreq; - // OSHttpResponse resp = objstate.oresp; - - // HandleRequest(request,resp); - // } - /// /// This methods is the start of incoming HTTP request handling. /// @@ -2036,7 +2026,7 @@ namespace OpenSim.Framework.Servers.HttpServer public void Start() { - Start(true,true); + Start(true, true); } /// @@ -2085,11 +2075,14 @@ namespace OpenSim.Framework.Servers.HttpServer //m_httpListener.Start(); m_httpListener2.Start(64); - // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events - if(runPool) + lock(m_generalLock) { - PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 2, 25000); - PollServiceRequestManager.Start(); + if (runPool) + { + if(m_pollServiceManager == null) + m_pollServiceManager = new PollServiceRequestManager(performPollResponsesAsync, 2, 25000); + m_pollServiceManager.Start(); + } } HTTPDRunning = true; @@ -2143,27 +2136,22 @@ namespace OpenSim.Framework.Servers.HttpServer if (source.ToString() == "HttpServer.HttpListener" && exception.ToString().StartsWith("Mono.Security.Protocol.Tls.TlsException")) return; m_log.ErrorFormat("[BASE HTTP SERVER]: {0} had an exception {1}", source.ToString(), exception.ToString()); - /* - if (HTTPDRunning)// && NotSocketErrors > 5) - { - Stop(); - Thread.Sleep(200); - StartHTTP(); - m_log.Warn("[HTTPSERVER]: Died. Trying to kick....."); - } - */ } - public void Stop() + public void Stop(bool stopPool = false) { HTTPDRunning = false; + StatsManager.DeregisterStat(m_requestsProcessedStat); try { - if(PollServiceRequestManager != null) - PollServiceRequestManager.Stop(); + lock(m_generalLock) + { + if (stopPool && m_pollServiceManager != null) + m_pollServiceManager.Stop(); + } m_httpListener2.ExceptionThrown -= httpServerException; //m_httpListener2.DisconnectHandler = null; diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs index 04eb8de58a..beeef7009a 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs @@ -79,12 +79,12 @@ namespace OpenSim.Framework.Servers.HttpServer contextHash = HttpContext.contextID; } - internal void DoHTTPGruntWork(BaseHttpServer server, Hashtable responsedata) + internal void DoHTTPGruntWork(Hashtable responsedata) { OSHttpResponse response = new OSHttpResponse(new HttpResponse(HttpContext, Request), HttpContext); - byte[] buffer = server.DoHTTPGruntWork(responsedata, response); + byte[] buffer = srvDoHTTPGruntWork(responsedata, response); if(Request.Body.CanRead) Request.Body.Dispose(); @@ -114,7 +114,119 @@ namespace OpenSim.Framework.Servers.HttpServer PollServiceArgs.RequestsHandled++; } - internal void DoHTTPstop(BaseHttpServer server) + internal byte[] srvDoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response) + { + int responsecode; + string responseString = String.Empty; + byte[] responseData = null; + string contentType; + + if (responsedata == null) + { + responsecode = 500; + responseString = "No response could be obtained"; + contentType = "text/plain"; + responsedata = new Hashtable(); + } + else + { + try + { + //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response"); + responsecode = (int)responsedata["int_response_code"]; + if (responsedata["bin_response_data"] != null) + responseData = (byte[])responsedata["bin_response_data"]; + else + responseString = (string)responsedata["str_response_string"]; + contentType = (string)responsedata["content_type"]; + if (responseString == null) + responseString = String.Empty; + } + catch + { + responsecode = 500; + responseString = "No response could be obtained"; + contentType = "text/plain"; + responsedata = new Hashtable(); + } + } + + if (responsedata.ContainsKey("error_status_text")) + { + response.StatusDescription = (string)responsedata["error_status_text"]; + } + if (responsedata.ContainsKey("http_protocol_version")) + { + response.ProtocolVersion = (string)responsedata["http_protocol_version"]; + } + + if (responsedata.ContainsKey("keepalive")) + { + bool keepalive = (bool)responsedata["keepalive"]; + response.KeepAlive = keepalive; + } + + // Cross-Origin Resource Sharing with simple requests + if (responsedata.ContainsKey("access_control_allow_origin")) + response.AddHeader("Access-Control-Allow-Origin", (string)responsedata["access_control_allow_origin"]); + + //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"; + } + + // The client ignores anything but 200 here for web login, so ensure that this is 200 for that + + response.StatusCode = responsecode; + + if (responsecode == (int)OSHttpStatusCode.RedirectMovedPermanently) + { + response.RedirectLocation = (string)responsedata["str_redirect_location"]; + response.StatusCode = responsecode; + } + + response.AddHeader("Content-Type", contentType); + if (responsedata.ContainsKey("headers")) + { + Hashtable headerdata = (Hashtable)responsedata["headers"]; + + foreach (string header in headerdata.Keys) + response.AddHeader(header, headerdata[header].ToString()); + } + + byte[] buffer; + + if (responseData != null) + { + buffer = responseData; + } + else + { + if (!(contentType.Contains("image") + || contentType.Contains("x-shockwave-flash") + || contentType.Contains("application/x-oar") + || contentType.Contains("application/vnd.ll.mesh"))) + { + // Text + buffer = Encoding.UTF8.GetBytes(responseString); + } + else + { + // Binary! + buffer = Convert.FromBase64String(responseString); + } + + response.SendChunked = false; + response.ContentLength64 = buffer.Length; + response.ContentEncoding = Encoding.UTF8; + } + + return buffer; + } + internal void DoHTTPstop() { OSHttpResponse response = new OSHttpResponse(new HttpResponse(HttpContext, Request), HttpContext); diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index ec16d7c26f..b9ac155401 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -41,8 +41,6 @@ namespace OpenSim.Framework.Servers.HttpServer { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private readonly BaseHttpServer m_server; - private Dictionary> m_bycontext; private BlockingCollection m_requests = new BlockingCollection(); private ConcurrentQueue m_retryRequests = new ConcurrentQueue(); @@ -56,9 +54,8 @@ namespace OpenSim.Framework.Servers.HttpServer private SmartThreadPool m_threadPool; public PollServiceRequestManager( - BaseHttpServer pSrv, bool performResponsesAsync, uint pWorkerThreadCount, int pTimeout) + bool performResponsesAsync, uint pWorkerThreadCount, int pTimeout) { - m_server = pSrv; m_WorkerThreadCount = pWorkerThreadCount; m_workerThreads = new Thread[m_WorkerThreadCount]; @@ -77,6 +74,8 @@ namespace OpenSim.Framework.Servers.HttpServer public void Start() { + if(m_running) + return; m_running = true; m_threadPool.Start(); //startup worker threads @@ -85,7 +84,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_workerThreads[i] = WorkManager.StartThread( PoolWorkerJob, - string.Format("PollServiceWorkerThread {0}:{1}", i, m_server.Port), + string.Format("PollServiceWorkerThread {0}", i), ThreadPriority.Normal, true, false, @@ -95,7 +94,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_retrysThread = WorkManager.StartThread( this.CheckRetries, - string.Format("PollServiceWatcherThread:{0}", m_server.Port), + string.Format("PollServiceWatcherThread"), ThreadPriority.Normal, true, true, @@ -183,6 +182,9 @@ namespace OpenSim.Framework.Servers.HttpServer public void Stop() { + if(!m_running) + return; + m_running = false; Thread.Sleep(100); // let the world move @@ -202,7 +204,7 @@ namespace OpenSim.Framework.Servers.HttpServer try { while(m_retryRequests.TryDequeue(out req)) - req.DoHTTPstop(m_server); + req.DoHTTPstop(); } catch { @@ -211,7 +213,7 @@ namespace OpenSim.Framework.Servers.HttpServer try { while(m_requests.TryTake(out req, 0)) - req.DoHTTPstop(m_server); + req.DoHTTPstop(); } catch { @@ -266,7 +268,7 @@ namespace OpenSim.Framework.Servers.HttpServer try { Hashtable responsedata = nreq.PollServiceArgs.GetEvents(nreq.RequestID, nreq.PollServiceArgs.Id); - nreq.DoHTTPGruntWork(m_server, responsedata); + nreq.DoHTTPGruntWork(responsedata); } catch (ObjectDisposedException) { } finally @@ -286,8 +288,7 @@ namespace OpenSim.Framework.Servers.HttpServer { try { - nreq.DoHTTPGruntWork(m_server, - nreq.PollServiceArgs.NoEvents(nreq.RequestID, nreq.PollServiceArgs.Id)); + nreq.DoHTTPGruntWork(nreq.PollServiceArgs.NoEvents(nreq.RequestID, nreq.PollServiceArgs.Id)); } catch (ObjectDisposedException) {} finally diff --git a/OpenSim/Framework/Servers/MainServer.cs b/OpenSim/Framework/Servers/MainServer.cs index 523ccba1cd..6a9be128f7 100644 --- a/OpenSim/Framework/Servers/MainServer.cs +++ b/OpenSim/Framework/Servers/MainServer.cs @@ -87,14 +87,15 @@ namespace OpenSim.Framework.Servers set { lock (m_Servers) + { if (!m_Servers.ContainsValue(value)) throw new Exception("HTTP server must already have been registered to be set as the main instance"); - instance = value; + instance = value; + } } } - public static BaseHttpServer UnSecureInstance { get { return unsecureinstance; } @@ -372,14 +373,14 @@ namespace OpenSim.Framework.Servers public static void Stop() { + PollServiceRequestManager pool = null; lock (m_Servers) { foreach (BaseHttpServer httpServer in m_Servers.Values) { - httpServer.Stop(); + httpServer.Stop(true); } } } - } } \ No newline at end of file