aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs329
1 files changed, 308 insertions, 21 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
index f57d857..ba917e39 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
@@ -27,11 +27,14 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using System.Collections.Specialized; 31using System.Collections.Specialized;
31using System.Reflection; 32using System.Reflection;
32using System.IO; 33using System.IO;
34using System.Threading;
33using System.Web; 35using System.Web;
34using Mono.Addins; 36using Mono.Addins;
37using OpenSim.Framework.Monitoring;
35using log4net; 38using log4net;
36using Nini.Config; 39using Nini.Config;
37using OpenMetaverse; 40using OpenMetaverse;
@@ -52,15 +55,46 @@ namespace OpenSim.Region.ClientStack.Linden
52 { 55 {
53// private static readonly ILog m_log = 56// private static readonly ILog m_log =
54// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 57// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55 58
56 private Scene m_scene; 59 private Scene m_scene;
57 private IAssetService m_AssetService; 60 private IAssetService m_AssetService;
58 private bool m_Enabled = true; 61 private bool m_Enabled = true;
59 private string m_URL; 62 private string m_URL;
63
60 private string m_URL2; 64 private string m_URL2;
61 private string m_RedirectURL = null; 65 private string m_RedirectURL = null;
62 private string m_RedirectURL2 = null; 66 private string m_RedirectURL2 = null;
63 67
68 struct aPollRequest
69 {
70 public PollServiceMeshEventArgs thepoll;
71 public UUID reqID;
72 public Hashtable request;
73 }
74
75 public class aPollResponse
76 {
77 public Hashtable response;
78 public int bytes;
79 public int lod;
80 }
81
82
83 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
84
85 private static GetMeshHandler m_getMeshHandler;
86
87 private IAssetService m_assetService = null;
88
89 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
90 private static Thread[] m_workerThreads = null;
91 private static int m_NumberScenes = 0;
92 private static OpenSim.Framework.BlockingQueue<aPollRequest> m_queue =
93 new OpenSim.Framework.BlockingQueue<aPollRequest>();
94
95 private Dictionary<UUID, PollServiceMeshEventArgs> m_pollservices = new Dictionary<UUID, PollServiceMeshEventArgs>();
96
97
64 #region Region Module interfaceBase Members 98 #region Region Module interfaceBase Members
65 99
66 public Type ReplaceableInterface 100 public Type ReplaceableInterface
@@ -87,6 +121,7 @@ namespace OpenSim.Region.ClientStack.Linden
87 if (m_URL2 != string.Empty) 121 if (m_URL2 != string.Empty)
88 { 122 {
89 m_Enabled = true; 123 m_Enabled = true;
124
90 m_RedirectURL2 = config.GetString("GetMesh2RedirectURL"); 125 m_RedirectURL2 = config.GetString("GetMesh2RedirectURL");
91 } 126 }
92 } 127 }
@@ -97,6 +132,8 @@ namespace OpenSim.Region.ClientStack.Linden
97 return; 132 return;
98 133
99 m_scene = pScene; 134 m_scene = pScene;
135
136 m_assetService = pScene.AssetService;
100 } 137 }
101 138
102 public void RemoveRegion(Scene scene) 139 public void RemoveRegion(Scene scene)
@@ -105,6 +142,9 @@ namespace OpenSim.Region.ClientStack.Linden
105 return; 142 return;
106 143
107 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 144 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
145 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
146 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
147 m_NumberScenes--;
108 m_scene = null; 148 m_scene = null;
109 } 149 }
110 150
@@ -115,55 +155,302 @@ namespace OpenSim.Region.ClientStack.Linden
115 155
116 m_AssetService = m_scene.RequestModuleInterface<IAssetService>(); 156 m_AssetService = m_scene.RequestModuleInterface<IAssetService>();
117 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 157 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
118 } 158 // We'll reuse the same handler for all requests.
159 m_getMeshHandler = new GetMeshHandler(m_assetService);
160 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
161 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
119 162
163 m_NumberScenes++;
164
165 if (m_workerThreads == null)
166 {
167 m_workerThreads = new Thread[2];
168
169 for (uint i = 0; i < 2; i++)
170 {
171 m_workerThreads[i] = WorkManager.StartThread(DoMeshRequests,
172 String.Format("GetMeshWorker{0}", i),
173 ThreadPriority.Normal,
174 true,
175 false,
176 null,
177 int.MaxValue);
178 }
179 }
180 }
120 181
121 public void Close() { } 182 public void Close()
183 {
184 if(m_NumberScenes <= 0 && m_workerThreads != null)
185 {
186 m_log.DebugFormat("[GetMeshModule] Closing");
187 foreach (Thread t in m_workerThreads)
188 Watchdog.AbortThread(t.ManagedThreadId);
189 // This will fail on region shutdown. Its harmless.
190 // Prevent red ink.
191 try
192 {
193 m_queue.Clear();
194 }
195 catch {}
196 }
197 }
122 198
123 public string Name { get { return "GetMeshModule"; } } 199 public string Name { get { return "GetMeshModule"; } }
124 200
125 #endregion 201 #endregion
126 202
203 private static void DoMeshRequests()
204 {
205 while(true)
206 {
207 aPollRequest poolreq = m_queue.Dequeue(4500);
208 Watchdog.UpdateThread();
209 if(m_NumberScenes <= 0)
210 return;
211 if(poolreq.reqID != UUID.Zero)
212 poolreq.thepoll.Process(poolreq);
213 }
214 }
127 215
128 public void RegisterCaps(UUID agentID, Caps caps) 216 // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent.
217 public void ThrottleUpdate(ScenePresence p)
129 { 218 {
130 UUID capID = UUID.Random(); 219 UUID user = p.UUID;
131 bool getMeshRegistered = false; 220 int imagethrottle = p.ControllingClient.GetAgentThrottleSilent((int)ThrottleOutPacketType.Asset);
221 PollServiceMeshEventArgs args;
222 if (m_pollservices.TryGetValue(user, out args))
223 {
224 args.UpdateThrottle(imagethrottle);
225 }
226 }
227
228 private class PollServiceMeshEventArgs : PollServiceEventArgs
229 {
230 private List<Hashtable> requests =
231 new List<Hashtable>();
232 private Dictionary<UUID, aPollResponse> responses =
233 new Dictionary<UUID, aPollResponse>();
234
235 private Scene m_scene;
236 private MeshCapsDataThrottler m_throttler;
237 public PollServiceMeshEventArgs(string uri, UUID pId, Scene scene) :
238 base(null, uri, null, null, null, pId, int.MaxValue)
239 {
240 m_scene = scene;
241 m_throttler = new MeshCapsDataThrottler(100000);
242 // x is request id, y is userid
243 HasEvents = (x, y) =>
244 {
245 lock (responses)
246 {
247 bool ret = m_throttler.hasEvents(x, responses);
248 return ret;
249
250 }
251 };
252 GetEvents = (x, y) =>
253 {
254 lock (responses)
255 {
256 try
257 {
258 return responses[x].response;
259 }
260 finally
261 {
262 responses.Remove(x);
263 m_throttler.PassTime();
264 }
265 }
266 };
267 // x is request id, y is request data hashtable
268 Request = (x, y) =>
269 {
270 aPollRequest reqinfo = new aPollRequest();
271 reqinfo.thepoll = this;
272 reqinfo.reqID = x;
273 reqinfo.request = y;
274
275 m_queue.Enqueue(reqinfo);
276 m_throttler.PassTime();
277 };
132 278
133 if (m_URL == string.Empty) 279 // this should never happen except possible on shutdown
280 NoEvents = (x, y) =>
281 {
282 /*
283 lock (requests)
284 {
285 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
286 requests.Remove(request);
287 }
288 */
289 Hashtable response = new Hashtable();
290
291 response["int_response_code"] = 500;
292 response["str_response_string"] = "Script timeout";
293 response["content_type"] = "text/plain";
294 response["keepalive"] = false;
295 response["reusecontext"] = false;
296
297 return response;
298 };
299 }
300
301 public void Process(aPollRequest requestinfo)
134 { 302 {
303 Hashtable response;
304
305 UUID requestID = requestinfo.reqID;
306
307 if(m_scene.ShuttingDown)
308 return;
309
310 // If the avatar is gone, don't bother to get the texture
311 if (m_scene.GetScenePresence(Id) == null)
312 {
313 response = new Hashtable();
314
315 response["int_response_code"] = 500;
316 response["str_response_string"] = "Script timeout";
317 response["content_type"] = "text/plain";
318 response["keepalive"] = false;
319 response["reusecontext"] = false;
320
321 lock (responses)
322 responses[requestID] = new aPollResponse() { bytes = 0, response = response, lod = 0 };
323
324 return;
325 }
326
327 response = m_getMeshHandler.Handle(requestinfo.request);
328 lock (responses)
329 {
330 responses[requestID] = new aPollResponse()
331 {
332 bytes = (int)response["int_bytes"],
333 lod = (int)response["int_lod"],
334 response = response
335 };
336
337 }
338 m_throttler.PassTime();
339 }
135 340
341 internal void UpdateThrottle(int pthrottle)
342 {
343 int tmp = 2 * pthrottle;
344 if(tmp < 10000)
345 tmp = 10000;
346 m_throttler.ThrottleBytes = tmp;
136 } 347 }
137 else if (m_URL == "localhost") 348 }
349
350 public void RegisterCaps(UUID agentID, Caps caps)
351 {
352// UUID capID = UUID.Random();
353 if (m_URL == "localhost")
138 { 354 {
139 getMeshRegistered = true; 355 string capUrl = "/CAPS/" + UUID.Random() + "/";
140 caps.RegisterHandler( 356
141 "GetMesh", 357 // Register this as a poll service
142 new GetMeshHandler("/CAPS/" + capID + "/", m_AssetService, "GetMesh", agentID.ToString(), m_RedirectURL)); 358 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(capUrl, agentID, m_scene);
359
360 args.Type = PollServiceEventArgs.EventType.Mesh;
361 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
362
363 string hostName = m_scene.RegionInfo.ExternalHostName;
364 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
365 string protocol = "http";
366
367 if (MainServer.Instance.UseSSL)
368 {
369 hostName = MainServer.Instance.SSLCommonName;
370 port = MainServer.Instance.SSLPort;
371 protocol = "https";
372 }
373 caps.RegisterHandler("GetMesh", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
374 m_pollservices[agentID] = args;
375 m_capsDict[agentID] = capUrl;
143 } 376 }
144 else 377 else
145 { 378 {
146 caps.RegisterHandler("GetMesh", m_URL); 379 caps.RegisterHandler("GetMesh", m_URL);
147 } 380 }
381 }
148 382
149 if(m_URL2 == string.Empty) 383 private void DeregisterCaps(UUID agentID, Caps caps)
384 {
385 string capUrl;
386 PollServiceMeshEventArgs args;
387 if (m_capsDict.TryGetValue(agentID, out capUrl))
388 {
389 MainServer.Instance.RemoveHTTPHandler("", capUrl);
390 m_capsDict.Remove(agentID);
391 }
392 if (m_pollservices.TryGetValue(agentID, out args))
150 { 393 {
394 m_pollservices.Remove(agentID);
395 }
396 }
397
398 internal sealed class MeshCapsDataThrottler
399 {
400 private double lastTimeElapsed = 0;
401 private double BytesSent = 0;
151 402
403 public MeshCapsDataThrottler(int pBytes)
404 {
405 if(pBytes < 10000)
406 pBytes = 10000;
407 ThrottleBytes = pBytes;
408 lastTimeElapsed = Util.GetTimeStampMS();
152 } 409 }
153 else if (m_URL2 == "localhost") 410
411 public bool hasEvents(UUID key, Dictionary<UUID, aPollResponse> responses)
154 { 412 {
155 if (!getMeshRegistered) 413 PassTime();
414 // Note, this is called IN LOCK
415 bool haskey = responses.ContainsKey(key);
416
417 if (!haskey)
418 {
419 return false;
420 }
421 aPollResponse response;
422 if (responses.TryGetValue(key, out response))
156 { 423 {
157 caps.RegisterHandler( 424 // Normal
158 "GetMesh2", 425 if (BytesSent <= ThrottleBytes)
159 new GetMeshHandler("/CAPS/" + capID + "/", m_AssetService, "GetMesh2", agentID.ToString(), m_RedirectURL2)); 426 {
427 BytesSent += response.bytes;
428 return true;
429 }
430 else
431 {
432 return false;
433 }
160 } 434 }
435 return haskey;
161 } 436 }
162 else 437
438 public void PassTime()
163 { 439 {
164 caps.RegisterHandler("GetMesh2", m_URL2); 440 double currenttime = Util.GetTimeStampMS();
441 double timeElapsed = currenttime - lastTimeElapsed;
442 if(timeElapsed < 50.0)
443 return;
444 int add = (int)(ThrottleBytes * timeElapsed * 0.001);
445 if (add >= 1000)
446 {
447 lastTimeElapsed = currenttime;
448 BytesSent -= add;
449 if (BytesSent < 0) BytesSent = 0;
450 }
165 } 451 }
166 }
167 452
453 public int ThrottleBytes;
454 }
168 } 455 }
169} 456}