diff --git a/OpenSim/Capabilities/Caps.cs b/OpenSim/Capabilities/Caps.cs index 7492602c46..82ecd55f04 100644 --- a/OpenSim/Capabilities/Caps.cs +++ b/OpenSim/Capabilities/Caps.cs @@ -207,6 +207,7 @@ namespace OpenSim.Framework.Capabilities { m_httpListener.RemovePollServiceHTTPHandler("", handler.Url); } + m_pollServiceHandlers.Clear(); } public bool TryGetPollHandler(string name, out PollServiceEventArgs pollHandler) diff --git a/OpenSim/Capabilities/Handlers/GetAssets/GetAssetsHandler.cs b/OpenSim/Capabilities/Handlers/GetAssets/GetAssetsHandler.cs new file mode 100644 index 0000000000..1f4e4ddba3 --- /dev/null +++ b/OpenSim/Capabilities/Handlers/GetAssets/GetAssetsHandler.cs @@ -0,0 +1,199 @@ +/* + * 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.Collections.Generic; +using System.Collections.Specialized; +using System.Reflection; +using System.IO; +using System.Web; +using log4net; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Services.Interfaces; +using Caps = OpenSim.Framework.Capabilities.Caps; + +namespace OpenSim.Capabilities.Handlers +{ + public class GetAssetsHandler + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private static readonly Dictionary queryTypes = new Dictionary() + { + {"texture_id", AssetType.Texture}, + {"sound_id", AssetType.Sound}, + {"callcard_id", AssetType.CallingCard}, + {"landmark_id", AssetType.Landmark}, + {"script_id", AssetType.LSLText}, + {"clothing_id", AssetType.Clothing}, + {"object_id", AssetType.Object}, + {"notecard_id", AssetType.Notecard}, + {"lsltext_id", AssetType.LSLText}, + {"lslbyte_id", AssetType.LSLBytecode}, + {"txtr_tga_id", AssetType.TextureTGA}, + {"bodypart_id", AssetType.Bodypart}, + {"snd_wav_id", AssetType.SoundWAV}, + {"img_tga_id", AssetType.ImageTGA}, + {"jpeg_id", AssetType.ImageJPEG}, + {"animatn_id", AssetType.Animation}, + {"gesture_id", AssetType.Gesture}, + {"mesh_id", AssetType.Mesh} + }; + + private IAssetService m_assetService; + + public GetAssetsHandler(IAssetService assService) + { + m_assetService = assService; + } + + public Hashtable Handle(Hashtable request) + { + Hashtable responsedata = new Hashtable(); + responsedata["content_type"] = "text/plain"; + responsedata["int_bytes"] = 0; + + if (m_assetService == null) + { + responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.ServiceUnavailable; + responsedata["str_response_string"] = "The asset service is unavailable"; + responsedata["keepalive"] = false; + return responsedata; + } + + responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.BadRequest; + + string[] queries = null; + if(request.Contains("querystringkeys")) + queries = (string[])request["querystringkeys"]; + + if(queries == null || queries.Length == 0) + return responsedata; + + string query = queries[0]; + if(!queryTypes.ContainsKey(query)) + { + m_log.Warn("[GETASSET]: Unknown type: " + query); + return responsedata; + } + + AssetType type = queryTypes[query]; + + string assetStr = string.Empty; + if (request.ContainsKey(query)) + assetStr = request[query].ToString(); + + if (String.IsNullOrEmpty(assetStr)) + return responsedata; + + UUID assetID = UUID.Zero; + if(!UUID.TryParse(assetStr, out assetID)) + return responsedata; + + AssetBase asset = m_assetService.Get(assetID.ToString()); + if(asset == null) + { + m_log.Warn("[GETASSET]: not found: " + query + " " + assetStr); + responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound; + responsedata["str_response_string"] = "Asset not found."; + return responsedata; + } + + if (asset.Type != (sbyte)type) + { + responsedata["str_response_string"] = "Got wrong asset type"; + return responsedata; + } + + if(type != AssetType.Mesh && type != AssetType.Texture) + m_log.Warn("[GETASSETS]: type: " + query); + + string range = String.Empty; + if (((Hashtable)request["headers"])["range"] != null) + range = (string)((Hashtable)request["headers"])["range"]; + else if (((Hashtable)request["headers"])["Range"] != null) + range = (string)((Hashtable)request["headers"])["Range"]; + + responsedata["content_type"] = asset.Metadata.ContentType; + + if (String.IsNullOrEmpty(range)) + { + // full asset + responsedata["bin_response_data"] = asset.Data; + responsedata["int_bytes"] = asset.Data.Length; + responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.OK; + return responsedata; + } + + // range request + int start, end; + if (Util.TryParseHttpRange(range, out start, out end)) + { + // Before clamping start make sure we can satisfy it in order to avoid + // sending back the last byte instead of an error status + if (start >= asset.Data.Length) + { + responsedata["str_response_string"] = "This range doesnt exist."; + return responsedata; + } + + if (end == -1) + end = asset.Data.Length - 1; + else + end = Utils.Clamp(end, 0, asset.Data.Length - 1); + + start = Utils.Clamp(start, 0, end); + int len = end - start + 1; + + //m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); + Hashtable headers = new Hashtable(); + headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end, asset.Data.Length); + responsedata["headers"] = headers; + responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.PartialContent; + + byte[] d = new byte[len]; + Array.Copy(asset.Data, start, d, 0, len); + responsedata["bin_response_data"] = d; + responsedata["int_bytes"] = len; + return responsedata; + } + + m_log.Warn("[GETASSETS]: Failed to parse a range, sending full asset: " + assetStr); + responsedata["bin_response_data"] = asset.Data; + responsedata["int_bytes"] = asset.Data.Length; + responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.OK; + return responsedata; + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index 7c7d08dbc0..ed7c0812a2 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs @@ -56,7 +56,9 @@ namespace OpenSim.Framework.Servers.HttpServer LslHttp = 1, Inventory = 2, Texture = 3, - Mesh = 4 + Mesh = 4, + Mesh2 = 5, + Asset = 6 } public string Url { get; set; } diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs index beeef7009a..cf4f835002 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs @@ -91,7 +91,6 @@ namespace OpenSim.Framework.Servers.HttpServer response.SendChunked = false; response.ContentLength64 = buffer.Length; - response.ContentEncoding = Encoding.UTF8; try { @@ -118,7 +117,7 @@ namespace OpenSim.Framework.Servers.HttpServer { int responsecode; string responseString = String.Empty; - byte[] responseData = null; + byte[] responseBytes = null; string contentType; if (responsedata == null) @@ -134,8 +133,9 @@ namespace OpenSim.Framework.Servers.HttpServer { //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"]; + responseBytes = (byte[])responsedata["bin_response_data"]; else responseString = (string)responsedata["str_response_string"]; contentType = (string)responsedata["content_type"]; @@ -170,9 +170,6 @@ namespace OpenSim.Framework.Servers.HttpServer 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"; @@ -185,7 +182,6 @@ namespace OpenSim.Framework.Servers.HttpServer if (responsecode == (int)OSHttpStatusCode.RedirectMovedPermanently) { response.RedirectLocation = (string)responsedata["str_redirect_location"]; - response.StatusCode = responsecode; } response.AddHeader("Content-Type", contentType); @@ -199,9 +195,9 @@ namespace OpenSim.Framework.Servers.HttpServer byte[] buffer; - if (responseData != null) + if (responseBytes != null) { - buffer = responseData; + buffer = responseBytes; } else { @@ -218,9 +214,6 @@ namespace OpenSim.Framework.Servers.HttpServer // Binary! buffer = Convert.FromBase64String(responseString); } - - response.SendChunked = false; - response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetAssetsModule.cs similarity index 60% rename from OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs rename to OpenSim/Region/ClientStack/Linden/Caps/GetAssetsModule.cs index b866e49824..51a6eccb3d 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetAssetsModule.cs @@ -47,20 +47,23 @@ using Caps = OpenSim.Framework.Capabilities.Caps; namespace OpenSim.Region.ClientStack.Linden { - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetMeshModule")] - public class GetMeshModule : INonSharedRegionModule + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetAssetsModule")] + public class GetAssetsModule : INonSharedRegionModule { // private static readonly ILog m_log = // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private Scene m_scene; - private bool m_Enabled = true; - private string m_URL; - private string m_URL2; + private bool m_Enabled; + + private string m_GetTextureURL; + private string m_GetMeshURL; + private string m_GetMesh2URL; + private string m_GetAssetURL; class APollRequest { - public PollServiceMeshEventArgs thepoll; + public PollServiceAssetEventArgs thepoll; public UUID reqID; public Hashtable request; } @@ -73,15 +76,17 @@ namespace OpenSim.Region.ClientStack.Linden private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private static GetMeshHandler m_getMeshHandler; - - private IAssetService m_assetService = null; - - private Dictionary m_capsDict = new Dictionary(); - private Dictionary m_capsDict2 = new Dictionary(); + private static IAssetService m_assetService = null; + private static GetAssetsHandler m_getAssetHandler; private static Thread[] m_workerThreads = null; private static int m_NumberScenes = 0; private static BlockingCollection m_queue = new BlockingCollection(); + private static object m_loadLock = new object(); + + private Dictionary m_capsDictTexture = new Dictionary(); + private Dictionary m_capsDictGetMesh = new Dictionary(); + private Dictionary m_capsDictGetMesh2 = new Dictionary(); + private Dictionary m_capsDictGetAsset = new Dictionary(); #region Region Module interfaceBase Members @@ -96,14 +101,20 @@ namespace OpenSim.Region.ClientStack.Linden if (config == null) return; - m_URL = config.GetString("Cap_GetMesh", string.Empty); - // Cap doesn't exist - if (m_URL != string.Empty) + m_GetTextureURL = config.GetString("Cap_GetTexture", string.Empty); + if (m_GetTextureURL != string.Empty) m_Enabled = true; - m_URL2 = config.GetString("Cap_GetMesh2", string.Empty); - // Cap doesn't exist - if (m_URL2 != string.Empty) + m_GetMeshURL = config.GetString("Cap_GetMesh", string.Empty); + if (m_GetMeshURL != string.Empty) + m_Enabled = true; + + m_GetMesh2URL = config.GetString("Cap_GetMesh2", string.Empty); + if (m_GetMesh2URL != string.Empty) + m_Enabled = true; + + m_GetAssetURL = config.GetString("Cap_GetAsset", string.Empty); + if (m_GetAssetURL != string.Empty) m_Enabled = true; } @@ -131,37 +142,39 @@ namespace OpenSim.Region.ClientStack.Linden if (!m_Enabled) return; - if(m_assetService == null) + lock(m_loadLock) { - m_assetService = m_scene.RequestModuleInterface(); - // We'll reuse the same handler for all requests. - if(m_assetService == null) + if (m_assetService == null && m_NumberScenes == 0) + { + m_assetService = s.RequestModuleInterface(); + // We'll reuse the same handler for all requests. + m_getAssetHandler = new GetAssetsHandler(m_assetService); + } + + if (m_assetService == null) { m_Enabled = false; return; } - m_getMeshHandler = new GetMeshHandler(m_assetService); - } + s.EventManager.OnRegisterCaps += RegisterCaps; + s.EventManager.OnDeregisterCaps += DeregisterCaps; - s.EventManager.OnRegisterCaps += RegisterCaps; - s.EventManager.OnDeregisterCaps += DeregisterCaps; + m_NumberScenes++; - m_NumberScenes++; - - if (m_workerThreads == null) - { - m_workerThreads = new Thread[2]; - - for (uint i = 0; i < 2; i++) + if (m_workerThreads == null) { - m_workerThreads[i] = WorkManager.StartThread(DoMeshRequests, - String.Format("GetMeshWorker{0}", i), - ThreadPriority.Normal, - true, - false, - null, - int.MaxValue); + m_workerThreads = new Thread[3]; + for (uint i = 0; i < 3; i++) + { + m_workerThreads[i] = WorkManager.StartThread(DoAssetRequests, + String.Format("GetAssetWorker{0}", i), + ThreadPriority.Normal, + true, + false, + null, + int.MaxValue); + } } } } @@ -170,7 +183,7 @@ namespace OpenSim.Region.ClientStack.Linden { if(m_NumberScenes <= 0 && m_workerThreads != null) { - m_log.DebugFormat("[GetMeshModule] Closing"); + m_log.DebugFormat("[GetAssetsModule] Closing"); foreach (Thread t in m_workerThreads) Watchdog.AbortThread(t.ManagedThreadId); // This will fail on region shutdown. Its harmless. @@ -183,38 +196,36 @@ namespace OpenSim.Region.ClientStack.Linden } } - public string Name { get { return "GetMeshModule"; } } + public string Name { get { return "GetAssetsModule"; } } #endregion - private static void DoMeshRequests() + private static void DoAssetRequests() { while (m_NumberScenes > 0) { APollRequest poolreq; if(m_queue.TryTake(out poolreq, 4500)) { - if(m_NumberScenes <= 0) + if (m_NumberScenes <= 0) break; - - if(poolreq.reqID != UUID.Zero) + Watchdog.UpdateThread(); + if (poolreq.reqID != UUID.Zero) poolreq.thepoll.Process(poolreq); } - Watchdog.UpdateThread(); + Watchdog.UpdateThread(); } } - private class PollServiceMeshEventArgs : PollServiceEventArgs + private class PollServiceAssetEventArgs : PollServiceEventArgs { - private List requests = - new List(); - private Dictionary responses = - new Dictionary(); + private List requests = new List(); + private Dictionary responses =new Dictionary(); private HashSet dropedResponses = new HashSet(); private Scene m_scene; private ScenePresence m_presence; - public PollServiceMeshEventArgs(string uri, UUID pId, Scene scene) : + public PollServiceAssetEventArgs(string uri, UUID pId, Scene scene) : base(null, uri, null, null, null, null, pId, int.MaxValue) { m_scene = scene; @@ -326,7 +337,7 @@ namespace OpenSim.Region.ClientStack.Linden } } - curresponse = m_getMeshHandler.Handle(requestinfo.request); + curresponse = m_getAssetHandler.Handle(requestinfo.request); lock(responses) { @@ -360,48 +371,108 @@ namespace OpenSim.Region.ClientStack.Linden protocol = "https"; } - if (m_URL == "localhost") + string baseURL = String.Format("{0}://{1}:{2}", protocol, hostName, port); + + if (m_GetTextureURL == "localhost") { string capUrl = "/CAPS/" + UUID.Random() + "/"; // Register this as a poll service - PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(capUrl, agentID, m_scene); - args.Type = PollServiceEventArgs.EventType.Mesh; + PollServiceAssetEventArgs args = new PollServiceAssetEventArgs(capUrl, agentID, m_scene); + + args.Type = PollServiceEventArgs.EventType.Texture; MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); - caps.RegisterHandler("GetMesh", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); - m_capsDict[agentID] = capUrl; + IExternalCapsModule handler = m_scene.RequestModuleInterface(); + if (handler != null) + handler.RegisterExternalUserCapsHandler(agentID, caps, "GetTexture", capUrl); + else + caps.RegisterHandler("GetTexture", baseURL + capUrl); + m_capsDictTexture[agentID] = capUrl; + } + else + { + caps.RegisterHandler("GetTexture", m_GetTextureURL); } - else if (m_URL != string.Empty) - caps.RegisterHandler("GetMesh", m_URL); - if (m_URL2 == "localhost") + //GetMesh + if (m_GetMeshURL == "localhost") { string capUrl = "/CAPS/" + UUID.Random() + "/"; - // Register this as a poll service - PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(capUrl, agentID, m_scene); + PollServiceAssetEventArgs args = new PollServiceAssetEventArgs(capUrl, agentID, m_scene); args.Type = PollServiceEventArgs.EventType.Mesh; MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); - caps.RegisterHandler("GetMesh2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); - m_capsDict2[agentID] = capUrl; + + IExternalCapsModule handler = m_scene.RequestModuleInterface(); + if (handler != null) + handler.RegisterExternalUserCapsHandler(agentID, caps, "GetMesh", capUrl); + else + caps.RegisterHandler("GetMesh", baseURL + capUrl); + m_capsDictGetMesh[agentID] = capUrl; } - else if(m_URL2 != string.Empty) - caps.RegisterHandler("GetMesh2", m_URL2); + else if (m_GetMeshURL != string.Empty) + caps.RegisterHandler("GetMesh", m_GetMeshURL); + + //GetMesh2 + if (m_GetMesh2URL == "localhost") + { + string capUrl = "/CAPS/" + UUID.Random() + "/"; + + PollServiceAssetEventArgs args = new PollServiceAssetEventArgs(capUrl, agentID, m_scene); + args.Type = PollServiceEventArgs.EventType.Mesh2; + MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); + IExternalCapsModule handler = m_scene.RequestModuleInterface(); + if (handler != null) + handler.RegisterExternalUserCapsHandler(agentID, caps, "GetMesh2", capUrl); + else + caps.RegisterHandler("GetMesh2", baseURL + capUrl); + m_capsDictGetMesh2[agentID] = capUrl; + } + else if (m_GetMesh2URL != string.Empty) + caps.RegisterHandler("GetMesh2", m_GetMesh2URL); + + //ViewerAsset + if (m_GetAssetURL == "localhost") + { + string capUrl = "/CAPS/" + UUID.Random() + "/"; + + PollServiceAssetEventArgs args = new PollServiceAssetEventArgs(capUrl, agentID, m_scene); + args.Type = PollServiceEventArgs.EventType.Asset; + MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); + IExternalCapsModule handler = m_scene.RequestModuleInterface(); + if (handler != null) + handler.RegisterExternalUserCapsHandler(agentID, caps, "ViewerAsset", capUrl); + else + caps.RegisterHandler("ViewerAsset", baseURL + capUrl); + m_capsDictGetAsset[agentID] = capUrl; + } + else if (m_GetAssetURL != string.Empty) + caps.RegisterHandler("ViewerAsset", m_GetMesh2URL); } private void DeregisterCaps(UUID agentID, Caps caps) { string capUrl; - if (m_capsDict.TryGetValue(agentID, out capUrl)) - { - MainServer.Instance.RemovePollServiceHTTPHandler("", capUrl); - m_capsDict.Remove(agentID); - } - if (m_capsDict2.TryGetValue(agentID, out capUrl)) + if (m_capsDictTexture.TryGetValue(agentID, out capUrl)) { MainServer.Instance.RemovePollServiceHTTPHandler("", capUrl); - m_capsDict2.Remove(agentID); + m_capsDictTexture.Remove(agentID); + } + if (m_capsDictGetMesh.TryGetValue(agentID, out capUrl)) + { + MainServer.Instance.RemovePollServiceHTTPHandler("", capUrl); + m_capsDictGetMesh.Remove(agentID); + } + if (m_capsDictGetMesh2.TryGetValue(agentID, out capUrl)) + { + MainServer.Instance.RemovePollServiceHTTPHandler("", capUrl); + m_capsDictGetMesh2.Remove(agentID); + } + if (m_capsDictGetAsset.TryGetValue(agentID, out capUrl)) + { + MainServer.Instance.RemovePollServiceHTTPHandler("", capUrl); + m_capsDictGetAsset.Remove(agentID); } } } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs deleted file mode 100644 index 87e23de354..0000000000 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs +++ /dev/null @@ -1,406 +0,0 @@ -/* - * 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.Collections.Generic; -using System.Collections.Concurrent; -using System.Reflection; -using System.Threading; -using log4net; -using Nini.Config; -using Mono.Addins; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Services.Interfaces; -using Caps = OpenSim.Framework.Capabilities.Caps; -using OpenSim.Capabilities.Handlers; -using OpenSim.Framework.Monitoring; - -namespace OpenSim.Region.ClientStack.Linden -{ - - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")] - public class GetTextureModule : INonSharedRegionModule - { - - class APollRequest - { - public PollServiceTextureEventArgs thepoll; - public UUID reqID; - public Hashtable request; - public bool send503; - } - - public class APollResponse - { - public Hashtable response; - public int bytes; - } - - - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private Scene m_scene; - - private static GetTextureHandler m_getTextureHandler; - - private IAssetService m_assetService = null; - - private Dictionary m_capsDict = new Dictionary(); - private static Thread[] m_workerThreads = null; - private static int m_NumberScenes = 0; - private static BlockingCollection m_queue = new BlockingCollection(); - - private Dictionary m_pollservices = new Dictionary(); - - private string m_Url = "localhost"; - - #region ISharedRegionModule Members - - public void Initialise(IConfigSource source) - { - IConfig config = source.Configs["ClientStack.LindenCaps"]; - - if (config == null) - return; -/* - m_URL = config.GetString("Cap_GetTexture", string.Empty); - // Cap doesn't exist - if (m_URL != string.Empty) - { - m_Enabled = true; - m_RedirectURL = config.GetString("GetTextureRedirectURL"); - } -*/ - m_Url = config.GetString("Cap_GetTexture", "localhost"); - } - - public void AddRegion(Scene s) - { - m_scene = s; - } - - public void RemoveRegion(Scene s) - { - s.EventManager.OnRegisterCaps -= RegisterCaps; - s.EventManager.OnDeregisterCaps -= DeregisterCaps; - m_NumberScenes--; - m_scene = null; - } - - public void RegionLoaded(Scene s) - { - if(m_assetService == null) - { - m_assetService = s.RequestModuleInterface(); - // We'll reuse the same handler for all requests. - m_getTextureHandler = new GetTextureHandler(m_assetService); - } - - s.EventManager.OnRegisterCaps += RegisterCaps; - s.EventManager.OnDeregisterCaps += DeregisterCaps; - - m_NumberScenes++; - - if (m_workerThreads == null) - { - m_workerThreads = new Thread[2]; - - for (uint i = 0; i < 2; i++) - { - m_workerThreads[i] = WorkManager.StartThread(DoTextureRequests, - String.Format("GetTextureWorker{0}", i), - ThreadPriority.Normal, - true, - false, - null, - int.MaxValue); - } - } - } - - public void PostInitialise() - { - } - - public void Close() - { - if(m_NumberScenes <= 0 && m_workerThreads != null) - { - m_log.DebugFormat("[GetTextureModule] Closing"); - - foreach (Thread t in m_workerThreads) - Watchdog.AbortThread(t.ManagedThreadId); - - m_queue.Dispose(); - } - } - - public string Name { get { return "GetTextureModule"; } } - - public Type ReplaceableInterface - { - get { return null; } - } - - #endregion - - private class PollServiceTextureEventArgs : PollServiceEventArgs - { - private List requests = - new List(); - private Dictionary responses = - new Dictionary(); - private HashSet dropedResponses = new HashSet(); - - private Scene m_scene; - private ScenePresence m_presence; - public PollServiceTextureEventArgs(UUID pId, Scene scene) : - base(null, "", null, null, null, null, pId, int.MaxValue) - { - m_scene = scene; - // x is request id, y is userid - HasEvents = (x, y) => - { - lock (responses) - { - APollResponse response; - if (responses.TryGetValue(x, out response)) - { - if (m_presence == null) - m_presence = m_scene.GetScenePresence(pId); - - if (m_presence == null || m_presence.IsDeleted) - return true; - return m_presence.CapCanSendAsset(0, response.bytes); - } - return false; - } - }; - - Drop = (x, y) => - { - lock (responses) - { - responses.Remove(x); - dropedResponses.Add(x); - } - }; - - GetEvents = (x, y) => - { - lock (responses) - { - try - { - return responses[x].response; - } - finally - { - responses.Remove(x); - } - } - }; - // x is request id, y is request data hashtable - Request = (x, y) => - { - APollRequest reqinfo = new APollRequest(); - reqinfo.thepoll = this; - reqinfo.reqID = x; - reqinfo.request = y; - reqinfo.send503 = false; - - lock (responses) - { - if (responses.Count > 0 && m_queue.Count > 32) - reqinfo.send503 = true; - } - - m_queue.Add(reqinfo); - }; - - // this should never happen except possible on shutdown - NoEvents = (x, y) => - { -/* - lock (requests) - { - Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString()); - requests.Remove(request); - } -*/ - Hashtable response = new Hashtable(); - - response["int_response_code"] = 500; - response["str_response_string"] = "timeout"; - response["content_type"] = "text/plain"; - response["keepalive"] = false; - return response; - }; - } - - public void Process(APollRequest requestinfo) - { - Hashtable response; - - UUID requestID = requestinfo.reqID; - - if(m_scene.ShuttingDown) - return; - - lock (responses) - { - lock(dropedResponses) - { - if(dropedResponses.Contains(requestID)) - { - dropedResponses.Remove(requestID); - return; - } - } - - if (m_presence == null) - m_presence = m_scene.GetScenePresence(Id); - - if (m_presence == null || m_presence.IsDeleted) - requestinfo.send503 = true; - - if (requestinfo.send503) - { - response = new Hashtable(); - - response["int_response_code"] = 503; - response["str_response_string"] = "Throttled"; - response["content_type"] = "text/plain"; - response["keepalive"] = false; - - Hashtable headers = new Hashtable(); - headers["Retry-After"] = 20; - response["headers"] = headers; - - responses[requestID] = new APollResponse() { bytes = 0, response = response }; - return; - } - } - - response = m_getTextureHandler.Handle(requestinfo.request); - - lock (responses) - { - lock(dropedResponses) - { - if(dropedResponses.Contains(requestID)) - { - dropedResponses.Remove(requestID); - return; - } - } - responses[requestID] = new APollResponse() - { - bytes = (int) response["int_bytes"], - response = response - }; - } - } - } - - private void RegisterCaps(UUID agentID, Caps caps) - { - if (m_Url == "localhost") - { - string capUrl = "/CAPS/" + UUID.Random() + "/"; - - // Register this as a poll service - PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene); - - args.Type = PollServiceEventArgs.EventType.Texture; - MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); - - string hostName = m_scene.RegionInfo.ExternalHostName; - uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; - string protocol = "http"; - - if (MainServer.Instance.UseSSL) - { - hostName = MainServer.Instance.SSLCommonName; - port = MainServer.Instance.SSLPort; - protocol = "https"; - } - IExternalCapsModule handler = m_scene.RequestModuleInterface(); - if (handler != null) - handler.RegisterExternalUserCapsHandler(agentID, caps, "GetTexture", capUrl); - else - caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); - m_pollservices[agentID] = args; - m_capsDict[agentID] = capUrl; - } - else - { - caps.RegisterHandler("GetTexture", m_Url); - } - } - - private void DeregisterCaps(UUID agentID, Caps caps) - { - PollServiceTextureEventArgs args; - - MainServer.Instance.RemoveHTTPHandler("", m_Url); - m_capsDict.Remove(agentID); - - if (m_pollservices.TryGetValue(agentID, out args)) - { - m_pollservices.Remove(agentID); - } - } - - private static void DoTextureRequests() - { - APollRequest poolreq; - while (m_NumberScenes > 0) - { - poolreq = null; - if(!m_queue.TryTake(out poolreq, 4500) || poolreq == null) - { - Watchdog.UpdateThread(); - continue; - } - - if(m_NumberScenes <= 0) - break; - - Watchdog.UpdateThread(); - if(poolreq.reqID != UUID.Zero) - poolreq.thepoll.Process(poolreq); - } - } - } -} diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index ca940b5580..c986233a95 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -398,22 +398,13 @@ namespace OpenSim.Region.ClientStack.Linden while (true) { APollRequest poolreq; - if (!m_queue.TryTake(out poolreq, 4500) || poolreq == null || poolreq.thepoll == null) + if (m_queue.TryTake(out poolreq, 4500)) { Watchdog.UpdateThread(); - continue; + if (poolreq.thepoll != null) + poolreq.thepoll.Process(poolreq); } - Watchdog.UpdateThread(); - try - { - poolreq.thepoll.Process(poolreq); - } - catch (Exception e) - { - m_log.ErrorFormat( - "[INVENTORY]: Failed to process queued inventory Exception {0}", e.Message); - } } } } diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 60db143827..2ee5534349 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -792,6 +792,7 @@ Cap_GetTexture = "localhost" Cap_GetMesh = "localhost" Cap_GetMesh2 = "localhost" + Cap_GetAsset = "localhost" Cap_GetObjectCost = "" Cap_GetObjectPhysicsData = "" Cap_GroupProposalBallot = ""