aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Capabilities/Caps.cs1
-rw-r--r--OpenSim/Capabilities/Handlers/GetAssets/GetAssetsHandler.cs199
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs4
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs17
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetAssetsModule.cs (renamed from OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs)217
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs406
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs15
7 files changed, 355 insertions, 504 deletions
diff --git a/OpenSim/Capabilities/Caps.cs b/OpenSim/Capabilities/Caps.cs
index 7492602..82ecd55 100644
--- a/OpenSim/Capabilities/Caps.cs
+++ b/OpenSim/Capabilities/Caps.cs
@@ -207,6 +207,7 @@ namespace OpenSim.Framework.Capabilities
207 { 207 {
208 m_httpListener.RemovePollServiceHTTPHandler("", handler.Url); 208 m_httpListener.RemovePollServiceHTTPHandler("", handler.Url);
209 } 209 }
210 m_pollServiceHandlers.Clear();
210 } 211 }
211 212
212 public bool TryGetPollHandler(string name, out PollServiceEventArgs pollHandler) 213 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 0000000..1f4e4dd
--- /dev/null
+++ b/OpenSim/Capabilities/Handlers/GetAssets/GetAssetsHandler.cs
@@ -0,0 +1,199 @@
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.Collections.Specialized;
32using System.Reflection;
33using System.IO;
34using System.Web;
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Framework;
40using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer;
42using OpenSim.Services.Interfaces;
43using Caps = OpenSim.Framework.Capabilities.Caps;
44
45namespace OpenSim.Capabilities.Handlers
46{
47 public class GetAssetsHandler
48 {
49 private static readonly ILog m_log =
50 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 private static readonly Dictionary<string, AssetType> queryTypes = new Dictionary<string, AssetType>()
53 {
54 {"texture_id", AssetType.Texture},
55 {"sound_id", AssetType.Sound},
56 {"callcard_id", AssetType.CallingCard},
57 {"landmark_id", AssetType.Landmark},
58 {"script_id", AssetType.LSLText},
59 {"clothing_id", AssetType.Clothing},
60 {"object_id", AssetType.Object},
61 {"notecard_id", AssetType.Notecard},
62 {"lsltext_id", AssetType.LSLText},
63 {"lslbyte_id", AssetType.LSLBytecode},
64 {"txtr_tga_id", AssetType.TextureTGA},
65 {"bodypart_id", AssetType.Bodypart},
66 {"snd_wav_id", AssetType.SoundWAV},
67 {"img_tga_id", AssetType.ImageTGA},
68 {"jpeg_id", AssetType.ImageJPEG},
69 {"animatn_id", AssetType.Animation},
70 {"gesture_id", AssetType.Gesture},
71 {"mesh_id", AssetType.Mesh}
72 };
73
74 private IAssetService m_assetService;
75
76 public GetAssetsHandler(IAssetService assService)
77 {
78 m_assetService = assService;
79 }
80
81 public Hashtable Handle(Hashtable request)
82 {
83 Hashtable responsedata = new Hashtable();
84 responsedata["content_type"] = "text/plain";
85 responsedata["int_bytes"] = 0;
86
87 if (m_assetService == null)
88 {
89 responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.ServiceUnavailable;
90 responsedata["str_response_string"] = "The asset service is unavailable";
91 responsedata["keepalive"] = false;
92 return responsedata;
93 }
94
95 responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.BadRequest;
96
97 string[] queries = null;
98 if(request.Contains("querystringkeys"))
99 queries = (string[])request["querystringkeys"];
100
101 if(queries == null || queries.Length == 0)
102 return responsedata;
103
104 string query = queries[0];
105 if(!queryTypes.ContainsKey(query))
106 {
107 m_log.Warn("[GETASSET]: Unknown type: " + query);
108 return responsedata;
109 }
110
111 AssetType type = queryTypes[query];
112
113 string assetStr = string.Empty;
114 if (request.ContainsKey(query))
115 assetStr = request[query].ToString();
116
117 if (String.IsNullOrEmpty(assetStr))
118 return responsedata;
119
120 UUID assetID = UUID.Zero;
121 if(!UUID.TryParse(assetStr, out assetID))
122 return responsedata;
123
124 AssetBase asset = m_assetService.Get(assetID.ToString());
125 if(asset == null)
126 {
127 m_log.Warn("[GETASSET]: not found: " + query + " " + assetStr);
128 responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
129 responsedata["str_response_string"] = "Asset not found.";
130 return responsedata;
131 }
132
133 if (asset.Type != (sbyte)type)
134 {
135 responsedata["str_response_string"] = "Got wrong asset type";
136 return responsedata;
137 }
138
139 if(type != AssetType.Mesh && type != AssetType.Texture)
140 m_log.Warn("[GETASSETS]: type: " + query);
141
142 string range = String.Empty;
143 if (((Hashtable)request["headers"])["range"] != null)
144 range = (string)((Hashtable)request["headers"])["range"];
145 else if (((Hashtable)request["headers"])["Range"] != null)
146 range = (string)((Hashtable)request["headers"])["Range"];
147
148 responsedata["content_type"] = asset.Metadata.ContentType;
149
150 if (String.IsNullOrEmpty(range))
151 {
152 // full asset
153 responsedata["bin_response_data"] = asset.Data;
154 responsedata["int_bytes"] = asset.Data.Length;
155 responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.OK;
156 return responsedata;
157 }
158
159 // range request
160 int start, end;
161 if (Util.TryParseHttpRange(range, out start, out end))
162 {
163 // Before clamping start make sure we can satisfy it in order to avoid
164 // sending back the last byte instead of an error status
165 if (start >= asset.Data.Length)
166 {
167 responsedata["str_response_string"] = "This range doesnt exist.";
168 return responsedata;
169 }
170
171 if (end == -1)
172 end = asset.Data.Length - 1;
173 else
174 end = Utils.Clamp(end, 0, asset.Data.Length - 1);
175
176 start = Utils.Clamp(start, 0, end);
177 int len = end - start + 1;
178
179 //m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
180 Hashtable headers = new Hashtable();
181 headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end, asset.Data.Length);
182 responsedata["headers"] = headers;
183 responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.PartialContent;
184
185 byte[] d = new byte[len];
186 Array.Copy(asset.Data, start, d, 0, len);
187 responsedata["bin_response_data"] = d;
188 responsedata["int_bytes"] = len;
189 return responsedata;
190 }
191
192 m_log.Warn("[GETASSETS]: Failed to parse a range, sending full asset: " + assetStr);
193 responsedata["bin_response_data"] = asset.Data;
194 responsedata["int_bytes"] = asset.Data.Length;
195 responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.OK;
196 return responsedata;
197 }
198 }
199} \ No newline at end of file
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
index 7c7d08d..ed7c081 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
@@ -56,7 +56,9 @@ namespace OpenSim.Framework.Servers.HttpServer
56 LslHttp = 1, 56 LslHttp = 1,
57 Inventory = 2, 57 Inventory = 2,
58 Texture = 3, 58 Texture = 3,
59 Mesh = 4 59 Mesh = 4,
60 Mesh2 = 5,
61 Asset = 6
60 } 62 }
61 63
62 public string Url { get; set; } 64 public string Url { get; set; }
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs
index beeef70..cf4f835 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs
@@ -91,7 +91,6 @@ namespace OpenSim.Framework.Servers.HttpServer
91 91
92 response.SendChunked = false; 92 response.SendChunked = false;
93 response.ContentLength64 = buffer.Length; 93 response.ContentLength64 = buffer.Length;
94 response.ContentEncoding = Encoding.UTF8;
95 94
96 try 95 try
97 { 96 {
@@ -118,7 +117,7 @@ namespace OpenSim.Framework.Servers.HttpServer
118 { 117 {
119 int responsecode; 118 int responsecode;
120 string responseString = String.Empty; 119 string responseString = String.Empty;
121 byte[] responseData = null; 120 byte[] responseBytes = null;
122 string contentType; 121 string contentType;
123 122
124 if (responsedata == null) 123 if (responsedata == null)
@@ -134,8 +133,9 @@ namespace OpenSim.Framework.Servers.HttpServer
134 { 133 {
135 //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response"); 134 //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response");
136 responsecode = (int)responsedata["int_response_code"]; 135 responsecode = (int)responsedata["int_response_code"];
136
137 if (responsedata["bin_response_data"] != null) 137 if (responsedata["bin_response_data"] != null)
138 responseData = (byte[])responsedata["bin_response_data"]; 138 responseBytes = (byte[])responsedata["bin_response_data"];
139 else 139 else
140 responseString = (string)responsedata["str_response_string"]; 140 responseString = (string)responsedata["str_response_string"];
141 contentType = (string)responsedata["content_type"]; 141 contentType = (string)responsedata["content_type"];
@@ -170,9 +170,6 @@ namespace OpenSim.Framework.Servers.HttpServer
170 if (responsedata.ContainsKey("access_control_allow_origin")) 170 if (responsedata.ContainsKey("access_control_allow_origin"))
171 response.AddHeader("Access-Control-Allow-Origin", (string)responsedata["access_control_allow_origin"]); 171 response.AddHeader("Access-Control-Allow-Origin", (string)responsedata["access_control_allow_origin"]);
172 172
173 //Even though only one other part of the entire code uses HTTPHandlers, we shouldn't expect this
174 //and should check for NullReferenceExceptions
175
176 if (string.IsNullOrEmpty(contentType)) 173 if (string.IsNullOrEmpty(contentType))
177 { 174 {
178 contentType = "text/html"; 175 contentType = "text/html";
@@ -185,7 +182,6 @@ namespace OpenSim.Framework.Servers.HttpServer
185 if (responsecode == (int)OSHttpStatusCode.RedirectMovedPermanently) 182 if (responsecode == (int)OSHttpStatusCode.RedirectMovedPermanently)
186 { 183 {
187 response.RedirectLocation = (string)responsedata["str_redirect_location"]; 184 response.RedirectLocation = (string)responsedata["str_redirect_location"];
188 response.StatusCode = responsecode;
189 } 185 }
190 186
191 response.AddHeader("Content-Type", contentType); 187 response.AddHeader("Content-Type", contentType);
@@ -199,9 +195,9 @@ namespace OpenSim.Framework.Servers.HttpServer
199 195
200 byte[] buffer; 196 byte[] buffer;
201 197
202 if (responseData != null) 198 if (responseBytes != null)
203 { 199 {
204 buffer = responseData; 200 buffer = responseBytes;
205 } 201 }
206 else 202 else
207 { 203 {
@@ -218,9 +214,6 @@ namespace OpenSim.Framework.Servers.HttpServer
218 // Binary! 214 // Binary!
219 buffer = Convert.FromBase64String(responseString); 215 buffer = Convert.FromBase64String(responseString);
220 } 216 }
221
222 response.SendChunked = false;
223 response.ContentLength64 = buffer.Length;
224 response.ContentEncoding = Encoding.UTF8; 217 response.ContentEncoding = Encoding.UTF8;
225 } 218 }
226 219
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetAssetsModule.cs
index b866e49..51a6ecc 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;
47 47
48namespace OpenSim.Region.ClientStack.Linden 48namespace OpenSim.Region.ClientStack.Linden
49{ 49{
50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetMeshModule")] 50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetAssetsModule")]
51 public class GetMeshModule : INonSharedRegionModule 51 public class GetAssetsModule : INonSharedRegionModule
52 { 52 {
53// private static readonly ILog m_log = 53// private static readonly ILog m_log =
54// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 54// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55 55
56 private Scene m_scene; 56 private Scene m_scene;
57 private bool m_Enabled = true; 57 private bool m_Enabled;
58 private string m_URL; 58
59 private string m_URL2; 59 private string m_GetTextureURL;
60 private string m_GetMeshURL;
61 private string m_GetMesh2URL;
62 private string m_GetAssetURL;
60 63
61 class APollRequest 64 class APollRequest
62 { 65 {
63 public PollServiceMeshEventArgs thepoll; 66 public PollServiceAssetEventArgs thepoll;
64 public UUID reqID; 67 public UUID reqID;
65 public Hashtable request; 68 public Hashtable request;
66 } 69 }
@@ -73,15 +76,17 @@ namespace OpenSim.Region.ClientStack.Linden
73 76
74 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 77 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
75 78
76 private static GetMeshHandler m_getMeshHandler; 79 private static IAssetService m_assetService = null;
77 80 private static GetAssetsHandler m_getAssetHandler;
78 private IAssetService m_assetService = null;
79
80 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
81 private Dictionary<UUID, string> m_capsDict2 = new Dictionary<UUID, string>();
82 private static Thread[] m_workerThreads = null; 81 private static Thread[] m_workerThreads = null;
83 private static int m_NumberScenes = 0; 82 private static int m_NumberScenes = 0;
84 private static BlockingCollection<APollRequest> m_queue = new BlockingCollection<APollRequest>(); 83 private static BlockingCollection<APollRequest> m_queue = new BlockingCollection<APollRequest>();
84 private static object m_loadLock = new object();
85
86 private Dictionary<UUID, string> m_capsDictTexture = new Dictionary<UUID, string>();
87 private Dictionary<UUID, string> m_capsDictGetMesh = new Dictionary<UUID, string>();
88 private Dictionary<UUID, string> m_capsDictGetMesh2 = new Dictionary<UUID, string>();
89 private Dictionary<UUID, string> m_capsDictGetAsset = new Dictionary<UUID, string>();
85 90
86 #region Region Module interfaceBase Members 91 #region Region Module interfaceBase Members
87 92
@@ -96,14 +101,20 @@ namespace OpenSim.Region.ClientStack.Linden
96 if (config == null) 101 if (config == null)
97 return; 102 return;
98 103
99 m_URL = config.GetString("Cap_GetMesh", string.Empty); 104 m_GetTextureURL = config.GetString("Cap_GetTexture", string.Empty);
100 // Cap doesn't exist 105 if (m_GetTextureURL != string.Empty)
101 if (m_URL != string.Empty) 106 m_Enabled = true;
107
108 m_GetMeshURL = config.GetString("Cap_GetMesh", string.Empty);
109 if (m_GetMeshURL != string.Empty)
102 m_Enabled = true; 110 m_Enabled = true;
103 111
104 m_URL2 = config.GetString("Cap_GetMesh2", string.Empty); 112 m_GetMesh2URL = config.GetString("Cap_GetMesh2", string.Empty);
105 // Cap doesn't exist 113 if (m_GetMesh2URL != string.Empty)
106 if (m_URL2 != string.Empty) 114 m_Enabled = true;
115
116 m_GetAssetURL = config.GetString("Cap_GetAsset", string.Empty);
117 if (m_GetAssetURL != string.Empty)
107 m_Enabled = true; 118 m_Enabled = true;
108 } 119 }
109 120
@@ -131,37 +142,39 @@ namespace OpenSim.Region.ClientStack.Linden
131 if (!m_Enabled) 142 if (!m_Enabled)
132 return; 143 return;
133 144
134 if(m_assetService == null) 145 lock(m_loadLock)
135 { 146 {
136 m_assetService = m_scene.RequestModuleInterface<IAssetService>(); 147 if (m_assetService == null && m_NumberScenes == 0)
137 // We'll reuse the same handler for all requests. 148 {
138 if(m_assetService == null) 149 m_assetService = s.RequestModuleInterface<IAssetService>();
150 // We'll reuse the same handler for all requests.
151 m_getAssetHandler = new GetAssetsHandler(m_assetService);
152 }
153
154 if (m_assetService == null)
139 { 155 {
140 m_Enabled = false; 156 m_Enabled = false;
141 return; 157 return;
142 } 158 }
143 159
144 m_getMeshHandler = new GetMeshHandler(m_assetService); 160 s.EventManager.OnRegisterCaps += RegisterCaps;
145 } 161 s.EventManager.OnDeregisterCaps += DeregisterCaps;
146
147 s.EventManager.OnRegisterCaps += RegisterCaps;
148 s.EventManager.OnDeregisterCaps += DeregisterCaps;
149
150 m_NumberScenes++;
151 162
152 if (m_workerThreads == null) 163 m_NumberScenes++;
153 {
154 m_workerThreads = new Thread[2];
155 164
156 for (uint i = 0; i < 2; i++) 165 if (m_workerThreads == null)
157 { 166 {
158 m_workerThreads[i] = WorkManager.StartThread(DoMeshRequests, 167 m_workerThreads = new Thread[3];
159 String.Format("GetMeshWorker{0}", i), 168 for (uint i = 0; i < 3; i++)
160 ThreadPriority.Normal, 169 {
161 true, 170 m_workerThreads[i] = WorkManager.StartThread(DoAssetRequests,
162 false, 171 String.Format("GetAssetWorker{0}", i),
163 null, 172 ThreadPriority.Normal,
164 int.MaxValue); 173 true,
174 false,
175 null,
176 int.MaxValue);
177 }
165 } 178 }
166 } 179 }
167 } 180 }
@@ -170,7 +183,7 @@ namespace OpenSim.Region.ClientStack.Linden
170 { 183 {
171 if(m_NumberScenes <= 0 && m_workerThreads != null) 184 if(m_NumberScenes <= 0 && m_workerThreads != null)
172 { 185 {
173 m_log.DebugFormat("[GetMeshModule] Closing"); 186 m_log.DebugFormat("[GetAssetsModule] Closing");
174 foreach (Thread t in m_workerThreads) 187 foreach (Thread t in m_workerThreads)
175 Watchdog.AbortThread(t.ManagedThreadId); 188 Watchdog.AbortThread(t.ManagedThreadId);
176 // This will fail on region shutdown. Its harmless. 189 // This will fail on region shutdown. Its harmless.
@@ -183,38 +196,36 @@ namespace OpenSim.Region.ClientStack.Linden
183 } 196 }
184 } 197 }
185 198
186 public string Name { get { return "GetMeshModule"; } } 199 public string Name { get { return "GetAssetsModule"; } }
187 200
188 #endregion 201 #endregion
189 202
190 private static void DoMeshRequests() 203 private static void DoAssetRequests()
191 { 204 {
192 while (m_NumberScenes > 0) 205 while (m_NumberScenes > 0)
193 { 206 {
194 APollRequest poolreq; 207 APollRequest poolreq;
195 if(m_queue.TryTake(out poolreq, 4500)) 208 if(m_queue.TryTake(out poolreq, 4500))
196 { 209 {
197 if(m_NumberScenes <= 0) 210 if (m_NumberScenes <= 0)
198 break; 211 break;
199 212 Watchdog.UpdateThread();
200 if(poolreq.reqID != UUID.Zero) 213 if (poolreq.reqID != UUID.Zero)
201 poolreq.thepoll.Process(poolreq); 214 poolreq.thepoll.Process(poolreq);
202 } 215 }
203 Watchdog.UpdateThread(); 216 Watchdog.UpdateThread();
204 } 217 }
205 } 218 }
206 219
207 private class PollServiceMeshEventArgs : PollServiceEventArgs 220 private class PollServiceAssetEventArgs : PollServiceEventArgs
208 { 221 {
209 private List<Hashtable> requests = 222 private List<Hashtable> requests = new List<Hashtable>();
210 new List<Hashtable>(); 223 private Dictionary<UUID, APollResponse> responses =new Dictionary<UUID, APollResponse>();
211 private Dictionary<UUID, APollResponse> responses =
212 new Dictionary<UUID, APollResponse>();
213 private HashSet<UUID> dropedResponses = new HashSet<UUID>(); 224 private HashSet<UUID> dropedResponses = new HashSet<UUID>();
214 225
215 private Scene m_scene; 226 private Scene m_scene;
216 private ScenePresence m_presence; 227 private ScenePresence m_presence;
217 public PollServiceMeshEventArgs(string uri, UUID pId, Scene scene) : 228 public PollServiceAssetEventArgs(string uri, UUID pId, Scene scene) :
218 base(null, uri, null, null, null, null, pId, int.MaxValue) 229 base(null, uri, null, null, null, null, pId, int.MaxValue)
219 { 230 {
220 m_scene = scene; 231 m_scene = scene;
@@ -326,7 +337,7 @@ namespace OpenSim.Region.ClientStack.Linden
326 } 337 }
327 } 338 }
328 339
329 curresponse = m_getMeshHandler.Handle(requestinfo.request); 340 curresponse = m_getAssetHandler.Handle(requestinfo.request);
330 341
331 lock(responses) 342 lock(responses)
332 { 343 {
@@ -360,48 +371,108 @@ namespace OpenSim.Region.ClientStack.Linden
360 protocol = "https"; 371 protocol = "https";
361 } 372 }
362 373
363 if (m_URL == "localhost") 374 string baseURL = String.Format("{0}://{1}:{2}", protocol, hostName, port);
375
376 if (m_GetTextureURL == "localhost")
364 { 377 {
365 string capUrl = "/CAPS/" + UUID.Random() + "/"; 378 string capUrl = "/CAPS/" + UUID.Random() + "/";
366 379
367 // Register this as a poll service 380 // Register this as a poll service
368 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(capUrl, agentID, m_scene); 381 PollServiceAssetEventArgs args = new PollServiceAssetEventArgs(capUrl, agentID, m_scene);
369 args.Type = PollServiceEventArgs.EventType.Mesh; 382
383 args.Type = PollServiceEventArgs.EventType.Texture;
370 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); 384 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
371 385
372 caps.RegisterHandler("GetMesh", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); 386 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
373 m_capsDict[agentID] = capUrl; 387 if (handler != null)
388 handler.RegisterExternalUserCapsHandler(agentID, caps, "GetTexture", capUrl);
389 else
390 caps.RegisterHandler("GetTexture", baseURL + capUrl);
391 m_capsDictTexture[agentID] = capUrl;
392 }
393 else
394 {
395 caps.RegisterHandler("GetTexture", m_GetTextureURL);
374 } 396 }
375 else if (m_URL != string.Empty)
376 caps.RegisterHandler("GetMesh", m_URL);
377 397
378 if (m_URL2 == "localhost") 398 //GetMesh
399 if (m_GetMeshURL == "localhost")
379 { 400 {
380 string capUrl = "/CAPS/" + UUID.Random() + "/"; 401 string capUrl = "/CAPS/" + UUID.Random() + "/";
381 402
382 // Register this as a poll service 403 PollServiceAssetEventArgs args = new PollServiceAssetEventArgs(capUrl, agentID, m_scene);
383 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(capUrl, agentID, m_scene);
384 args.Type = PollServiceEventArgs.EventType.Mesh; 404 args.Type = PollServiceEventArgs.EventType.Mesh;
385 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); 405 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
386 caps.RegisterHandler("GetMesh2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); 406
387 m_capsDict2[agentID] = capUrl; 407 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
408 if (handler != null)
409 handler.RegisterExternalUserCapsHandler(agentID, caps, "GetMesh", capUrl);
410 else
411 caps.RegisterHandler("GetMesh", baseURL + capUrl);
412 m_capsDictGetMesh[agentID] = capUrl;
388 } 413 }
389 else if(m_URL2 != string.Empty) 414 else if (m_GetMeshURL != string.Empty)
390 caps.RegisterHandler("GetMesh2", m_URL2); 415 caps.RegisterHandler("GetMesh", m_GetMeshURL);
416
417 //GetMesh2
418 if (m_GetMesh2URL == "localhost")
419 {
420 string capUrl = "/CAPS/" + UUID.Random() + "/";
421
422 PollServiceAssetEventArgs args = new PollServiceAssetEventArgs(capUrl, agentID, m_scene);
423 args.Type = PollServiceEventArgs.EventType.Mesh2;
424 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
425 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
426 if (handler != null)
427 handler.RegisterExternalUserCapsHandler(agentID, caps, "GetMesh2", capUrl);
428 else
429 caps.RegisterHandler("GetMesh2", baseURL + capUrl);
430 m_capsDictGetMesh2[agentID] = capUrl;
431 }
432 else if (m_GetMesh2URL != string.Empty)
433 caps.RegisterHandler("GetMesh2", m_GetMesh2URL);
434
435 //ViewerAsset
436 if (m_GetAssetURL == "localhost")
437 {
438 string capUrl = "/CAPS/" + UUID.Random() + "/";
439
440 PollServiceAssetEventArgs args = new PollServiceAssetEventArgs(capUrl, agentID, m_scene);
441 args.Type = PollServiceEventArgs.EventType.Asset;
442 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
443 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
444 if (handler != null)
445 handler.RegisterExternalUserCapsHandler(agentID, caps, "ViewerAsset", capUrl);
446 else
447 caps.RegisterHandler("ViewerAsset", baseURL + capUrl);
448 m_capsDictGetAsset[agentID] = capUrl;
449 }
450 else if (m_GetAssetURL != string.Empty)
451 caps.RegisterHandler("ViewerAsset", m_GetMesh2URL);
391 } 452 }
392 453
393 private void DeregisterCaps(UUID agentID, Caps caps) 454 private void DeregisterCaps(UUID agentID, Caps caps)
394 { 455 {
395 string capUrl; 456 string capUrl;
396 if (m_capsDict.TryGetValue(agentID, out capUrl)) 457 if (m_capsDictTexture.TryGetValue(agentID, out capUrl))
458 {
459 MainServer.Instance.RemovePollServiceHTTPHandler("", capUrl);
460 m_capsDictTexture.Remove(agentID);
461 }
462 if (m_capsDictGetMesh.TryGetValue(agentID, out capUrl))
397 { 463 {
398 MainServer.Instance.RemovePollServiceHTTPHandler("", capUrl); 464 MainServer.Instance.RemovePollServiceHTTPHandler("", capUrl);
399 m_capsDict.Remove(agentID); 465 m_capsDictGetMesh.Remove(agentID);
466 }
467 if (m_capsDictGetMesh2.TryGetValue(agentID, out capUrl))
468 {
469 MainServer.Instance.RemovePollServiceHTTPHandler("", capUrl);
470 m_capsDictGetMesh2.Remove(agentID);
400 } 471 }
401 if (m_capsDict2.TryGetValue(agentID, out capUrl)) 472 if (m_capsDictGetAsset.TryGetValue(agentID, out capUrl))
402 { 473 {
403 MainServer.Instance.RemovePollServiceHTTPHandler("", capUrl); 474 MainServer.Instance.RemovePollServiceHTTPHandler("", capUrl);
404 m_capsDict2.Remove(agentID); 475 m_capsDictGetAsset.Remove(agentID);
405 } 476 }
406 } 477 }
407 } 478 }
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
deleted file mode 100644
index 87e23de..0000000
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
+++ /dev/null
@@ -1,406 +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.Collections.Concurrent;
32using System.Reflection;
33using System.Threading;
34using log4net;
35using Nini.Config;
36using Mono.Addins;
37using OpenMetaverse;
38using OpenSim.Framework;
39using OpenSim.Framework.Servers;
40using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Services.Interfaces;
44using Caps = OpenSim.Framework.Capabilities.Caps;
45using OpenSim.Capabilities.Handlers;
46using OpenSim.Framework.Monitoring;
47
48namespace OpenSim.Region.ClientStack.Linden
49{
50
51 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")]
52 public class GetTextureModule : INonSharedRegionModule
53 {
54
55 class APollRequest
56 {
57 public PollServiceTextureEventArgs thepoll;
58 public UUID reqID;
59 public Hashtable request;
60 public bool send503;
61 }
62
63 public class APollResponse
64 {
65 public Hashtable response;
66 public int bytes;
67 }
68
69
70 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
71
72 private Scene m_scene;
73
74 private static GetTextureHandler m_getTextureHandler;
75
76 private IAssetService m_assetService = null;
77
78 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
79 private static Thread[] m_workerThreads = null;
80 private static int m_NumberScenes = 0;
81 private static BlockingCollection<APollRequest> m_queue = new BlockingCollection<APollRequest>();
82
83 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>();
84
85 private string m_Url = "localhost";
86
87 #region ISharedRegionModule Members
88
89 public void Initialise(IConfigSource source)
90 {
91 IConfig config = source.Configs["ClientStack.LindenCaps"];
92
93 if (config == null)
94 return;
95/*
96 m_URL = config.GetString("Cap_GetTexture", string.Empty);
97 // Cap doesn't exist
98 if (m_URL != string.Empty)
99 {
100 m_Enabled = true;
101 m_RedirectURL = config.GetString("GetTextureRedirectURL");
102 }
103*/
104 m_Url = config.GetString("Cap_GetTexture", "localhost");
105 }
106
107 public void AddRegion(Scene s)
108 {
109 m_scene = s;
110 }
111
112 public void RemoveRegion(Scene s)
113 {
114 s.EventManager.OnRegisterCaps -= RegisterCaps;
115 s.EventManager.OnDeregisterCaps -= DeregisterCaps;
116 m_NumberScenes--;
117 m_scene = null;
118 }
119
120 public void RegionLoaded(Scene s)
121 {
122 if(m_assetService == null)
123 {
124 m_assetService = s.RequestModuleInterface<IAssetService>();
125 // We'll reuse the same handler for all requests.
126 m_getTextureHandler = new GetTextureHandler(m_assetService);
127 }
128
129 s.EventManager.OnRegisterCaps += RegisterCaps;
130 s.EventManager.OnDeregisterCaps += DeregisterCaps;
131
132 m_NumberScenes++;
133
134 if (m_workerThreads == null)
135 {
136 m_workerThreads = new Thread[2];
137
138 for (uint i = 0; i < 2; i++)
139 {
140 m_workerThreads[i] = WorkManager.StartThread(DoTextureRequests,
141 String.Format("GetTextureWorker{0}", i),
142 ThreadPriority.Normal,
143 true,
144 false,
145 null,
146 int.MaxValue);
147 }
148 }
149 }
150
151 public void PostInitialise()
152 {
153 }
154
155 public void Close()
156 {
157 if(m_NumberScenes <= 0 && m_workerThreads != null)
158 {
159 m_log.DebugFormat("[GetTextureModule] Closing");
160
161 foreach (Thread t in m_workerThreads)
162 Watchdog.AbortThread(t.ManagedThreadId);
163
164 m_queue.Dispose();
165 }
166 }
167
168 public string Name { get { return "GetTextureModule"; } }
169
170 public Type ReplaceableInterface
171 {
172 get { return null; }
173 }
174
175 #endregion
176
177 private class PollServiceTextureEventArgs : PollServiceEventArgs
178 {
179 private List<Hashtable> requests =
180 new List<Hashtable>();
181 private Dictionary<UUID, APollResponse> responses =
182 new Dictionary<UUID, APollResponse>();
183 private HashSet<UUID> dropedResponses = new HashSet<UUID>();
184
185 private Scene m_scene;
186 private ScenePresence m_presence;
187 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
188 base(null, "", null, null, null, null, pId, int.MaxValue)
189 {
190 m_scene = scene;
191 // x is request id, y is userid
192 HasEvents = (x, y) =>
193 {
194 lock (responses)
195 {
196 APollResponse response;
197 if (responses.TryGetValue(x, out response))
198 {
199 if (m_presence == null)
200 m_presence = m_scene.GetScenePresence(pId);
201
202 if (m_presence == null || m_presence.IsDeleted)
203 return true;
204 return m_presence.CapCanSendAsset(0, response.bytes);
205 }
206 return false;
207 }
208 };
209
210 Drop = (x, y) =>
211 {
212 lock (responses)
213 {
214 responses.Remove(x);
215 dropedResponses.Add(x);
216 }
217 };
218
219 GetEvents = (x, y) =>
220 {
221 lock (responses)
222 {
223 try
224 {
225 return responses[x].response;
226 }
227 finally
228 {
229 responses.Remove(x);
230 }
231 }
232 };
233 // x is request id, y is request data hashtable
234 Request = (x, y) =>
235 {
236 APollRequest reqinfo = new APollRequest();
237 reqinfo.thepoll = this;
238 reqinfo.reqID = x;
239 reqinfo.request = y;
240 reqinfo.send503 = false;
241
242 lock (responses)
243 {
244 if (responses.Count > 0 && m_queue.Count > 32)
245 reqinfo.send503 = true;
246 }
247
248 m_queue.Add(reqinfo);
249 };
250
251 // this should never happen except possible on shutdown
252 NoEvents = (x, y) =>
253 {
254/*
255 lock (requests)
256 {
257 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
258 requests.Remove(request);
259 }
260*/
261 Hashtable response = new Hashtable();
262
263 response["int_response_code"] = 500;
264 response["str_response_string"] = "timeout";
265 response["content_type"] = "text/plain";
266 response["keepalive"] = false;
267 return response;
268 };
269 }
270
271 public void Process(APollRequest requestinfo)
272 {
273 Hashtable response;
274
275 UUID requestID = requestinfo.reqID;
276
277 if(m_scene.ShuttingDown)
278 return;
279
280 lock (responses)
281 {
282 lock(dropedResponses)
283 {
284 if(dropedResponses.Contains(requestID))
285 {
286 dropedResponses.Remove(requestID);
287 return;
288 }
289 }
290
291 if (m_presence == null)
292 m_presence = m_scene.GetScenePresence(Id);
293
294 if (m_presence == null || m_presence.IsDeleted)
295 requestinfo.send503 = true;
296
297 if (requestinfo.send503)
298 {
299 response = new Hashtable();
300
301 response["int_response_code"] = 503;
302 response["str_response_string"] = "Throttled";
303 response["content_type"] = "text/plain";
304 response["keepalive"] = false;
305
306 Hashtable headers = new Hashtable();
307 headers["Retry-After"] = 20;
308 response["headers"] = headers;
309
310 responses[requestID] = new APollResponse() { bytes = 0, response = response };
311 return;
312 }
313 }
314
315 response = m_getTextureHandler.Handle(requestinfo.request);
316
317 lock (responses)
318 {
319 lock(dropedResponses)
320 {
321 if(dropedResponses.Contains(requestID))
322 {
323 dropedResponses.Remove(requestID);
324 return;
325 }
326 }
327 responses[requestID] = new APollResponse()
328 {
329 bytes = (int) response["int_bytes"],
330 response = response
331 };
332 }
333 }
334 }
335
336 private void RegisterCaps(UUID agentID, Caps caps)
337 {
338 if (m_Url == "localhost")
339 {
340 string capUrl = "/CAPS/" + UUID.Random() + "/";
341
342 // Register this as a poll service
343 PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene);
344
345 args.Type = PollServiceEventArgs.EventType.Texture;
346 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
347
348 string hostName = m_scene.RegionInfo.ExternalHostName;
349 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
350 string protocol = "http";
351
352 if (MainServer.Instance.UseSSL)
353 {
354 hostName = MainServer.Instance.SSLCommonName;
355 port = MainServer.Instance.SSLPort;
356 protocol = "https";
357 }
358 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
359 if (handler != null)
360 handler.RegisterExternalUserCapsHandler(agentID, caps, "GetTexture", capUrl);
361 else
362 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
363 m_pollservices[agentID] = args;
364 m_capsDict[agentID] = capUrl;
365 }
366 else
367 {
368 caps.RegisterHandler("GetTexture", m_Url);
369 }
370 }
371
372 private void DeregisterCaps(UUID agentID, Caps caps)
373 {
374 PollServiceTextureEventArgs args;
375
376 MainServer.Instance.RemoveHTTPHandler("", m_Url);
377 m_capsDict.Remove(agentID);
378
379 if (m_pollservices.TryGetValue(agentID, out args))
380 {
381 m_pollservices.Remove(agentID);
382 }
383 }
384
385 private static void DoTextureRequests()
386 {
387 APollRequest poolreq;
388 while (m_NumberScenes > 0)
389 {
390 poolreq = null;
391 if(!m_queue.TryTake(out poolreq, 4500) || poolreq == null)
392 {
393 Watchdog.UpdateThread();
394 continue;
395 }
396
397 if(m_NumberScenes <= 0)
398 break;
399
400 Watchdog.UpdateThread();
401 if(poolreq.reqID != UUID.Zero)
402 poolreq.thepoll.Process(poolreq);
403 }
404 }
405 }
406}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
index ca940b5..c986233 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
398 while (true) 398 while (true)
399 { 399 {
400 APollRequest poolreq; 400 APollRequest poolreq;
401 if (!m_queue.TryTake(out poolreq, 4500) || poolreq == null || poolreq.thepoll == null) 401 if (m_queue.TryTake(out poolreq, 4500))
402 { 402 {
403 Watchdog.UpdateThread(); 403 Watchdog.UpdateThread();
404 continue; 404 if (poolreq.thepoll != null)
405 poolreq.thepoll.Process(poolreq);
405 } 406 }
406
407 Watchdog.UpdateThread(); 407 Watchdog.UpdateThread();
408 try
409 {
410 poolreq.thepoll.Process(poolreq);
411 }
412 catch (Exception e)
413 {
414 m_log.ErrorFormat(
415 "[INVENTORY]: Failed to process queued inventory Exception {0}", e.Message);
416 }
417 } 408 }
418 } 409 }
419 } 410 }