aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden
diff options
context:
space:
mode:
authorMelanie Thielker2014-06-21 00:39:55 +0200
committerMelanie Thielker2014-06-21 00:39:55 +0200
commit159fcbf150b7da0e229b29aa7b94793484543d12 (patch)
treeb8c0ff3b4c758a3fba8315b556c923ef4c02a185 /OpenSim/Region/ClientStack/Linden
parentMerge commit '68c8633ba18f0a11cfc0ed04d1d0c7c59e6cec76' (diff)
parentMerge branch 'master' into careminster (diff)
downloadopensim-SC-159fcbf150b7da0e229b29aa7b94793484543d12.zip
opensim-SC-159fcbf150b7da0e229b29aa7b94793484543d12.tar.gz
opensim-SC-159fcbf150b7da0e229b29aa7b94793484543d12.tar.bz2
opensim-SC-159fcbf150b7da0e229b29aa7b94793484543d12.tar.xz
Merge branch 'master' of ssh://3dhosting.de/var/git/careminster
Conflicts: OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs136
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs27
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs147
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs36
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs8
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs6
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs20
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs4
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs1
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs26
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs44
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs115
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs4
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs719
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs7
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs110
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs628
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs111
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs25
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs6
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs16
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs9
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs6
26 files changed, 1641 insertions, 576 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs
new file mode 100644
index 0000000..bbadc55
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs
@@ -0,0 +1,136 @@
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.Specialized;
31using System.Drawing;
32using System.Drawing.Imaging;
33using System.Reflection;
34using System.IO;
35using System.Web;
36using log4net;
37using Nini.Config;
38using Mono.Addins;
39using OpenMetaverse;
40using OpenMetaverse.StructuredData;
41using OpenSim.Framework;
42using OpenSim.Framework.Servers;
43using OpenSim.Framework.Servers.HttpServer;
44using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Region.Framework.Scenes;
46using OpenSim.Services.Interfaces;
47using Caps = OpenSim.Framework.Capabilities.Caps;
48using OpenSim.Capabilities.Handlers;
49
50namespace OpenSim.Region.ClientStack.Linden
51{
52 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AvatarPickerSearchModule")]
53 public class AvatarPickerSearchModule : INonSharedRegionModule
54 {
55// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56
57 private Scene m_scene;
58 private IPeople m_People;
59 private bool m_Enabled = false;
60
61 private string m_URL;
62
63 #region ISharedRegionModule Members
64
65 public void Initialise(IConfigSource source)
66 {
67 IConfig config = source.Configs["ClientStack.LindenCaps"];
68 if (config == null)
69 return;
70
71 m_URL = config.GetString("Cap_AvatarPickerSearch", string.Empty);
72 // Cap doesn't exist
73 if (m_URL != string.Empty)
74 m_Enabled = true;
75 }
76
77 public void AddRegion(Scene s)
78 {
79 if (!m_Enabled)
80 return;
81
82 m_scene = s;
83 }
84
85 public void RemoveRegion(Scene s)
86 {
87 if (!m_Enabled)
88 return;
89
90 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
91 m_scene = null;
92 }
93
94 public void RegionLoaded(Scene s)
95 {
96 if (!m_Enabled)
97 return;
98
99 m_People = m_scene.RequestModuleInterface<IPeople>();
100 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
101 }
102
103 public void PostInitialise()
104 {
105 }
106
107 public void Close() { }
108
109 public string Name { get { return "AvatarPickerSearchModule"; } }
110
111 public Type ReplaceableInterface
112 {
113 get { return null; }
114 }
115
116 #endregion
117
118 public void RegisterCaps(UUID agentID, Caps caps)
119 {
120 UUID capID = UUID.Random();
121
122 if (m_URL == "localhost")
123 {
124// m_log.DebugFormat("[AVATAR PICKER SEARCH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
125 caps.RegisterHandler(
126 "AvatarPickerSearch",
127 new AvatarPickerSearchHandler("/CAPS/" + capID + "/", m_People, "AvatarPickerSearch", "Search for avatars by name"));
128 }
129 else
130 {
131 // m_log.DebugFormat("[AVATAR PICKER SEARCH]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName);
132 caps.RegisterHandler("AvatarPickerSearch", m_URL);
133 }
134 }
135 }
136} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 8241e07..613bc24 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -282,13 +282,19 @@ namespace OpenSim.Region.ClientStack.Linden
282 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); 282 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
283 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); 283 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
284 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); 284 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
285 IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData); 285
286 IRequestHandler getObjectPhysicsDataHandler
287 = new RestStreamHandler(
288 "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null);
286 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); 289 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
287 IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost); 290 IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost);
288 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler); 291 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler);
289 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected); 292 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected);
290 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler); 293 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler);
291 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation); 294
295 IRequestHandler UpdateAgentInformationHandler
296 = new RestStreamHandler(
297 "POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation, "UpdateAgentInformation", null);
292 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); 298 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler);
293 299
294 m_HostCapsObj.RegisterHandler( 300 m_HostCapsObj.RegisterHandler(
@@ -361,18 +367,7 @@ namespace OpenSim.Region.ClientStack.Linden
361 foreach (OSD c in capsRequested) 367 foreach (OSD c in capsRequested)
362 validCaps.Add(c.AsString()); 368 validCaps.Add(c.AsString());
363 369
364 Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true, validCaps); 370 string result = LLSDHelpers.SerialiseLLSDReply(m_HostCapsObj.GetCapsDetails(true, validCaps));
365
366 // Add the external too
367 foreach (KeyValuePair<string, string> kvp in m_HostCapsObj.ExternalCapsHandlers)
368 {
369 if (!validCaps.Contains(kvp.Key))
370 continue;
371
372 caps[kvp.Key] = kvp.Value;
373 }
374
375 string result = LLSDHelpers.SerialiseLLSDReply(caps);
376 371
377 //m_log.DebugFormat("[CAPS] CapsRequest {0}", result); 372 //m_log.DebugFormat("[CAPS] CapsRequest {0}", result);
378 373
@@ -748,6 +743,10 @@ namespace OpenSim.Region.ClientStack.Linden
748 inType = (sbyte)InventoryType.Sound; 743 inType = (sbyte)InventoryType.Sound;
749 assType = (sbyte)AssetType.Sound; 744 assType = (sbyte)AssetType.Sound;
750 } 745 }
746 else if (inventoryType == "snapshot")
747 {
748 inType = (sbyte)InventoryType.Snapshot;
749 }
751 else if (inventoryType == "animation") 750 else if (inventoryType == "animation")
752 { 751 {
753 inType = (sbyte)InventoryType.Animation; 752 inType = (sbyte)InventoryType.Animation;
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
index eb40eb1..ffb53af 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -65,6 +65,13 @@ namespace OpenSim.Region.ClientStack.Linden
65 /// </value> 65 /// </value>
66 public int DebugLevel { get; set; } 66 public int DebugLevel { get; set; }
67 67
68 // Viewer post requests timeout in 60 secs
69 // https://bitbucket.org/lindenlab/viewer-release/src/421c20423df93d650cc305dc115922bb30040999/indra/llmessage/llhttpclient.cpp?at=default#cl-44
70 //
71 private const int VIEWER_TIMEOUT = 60 * 1000;
72 // Just to be safe, we work on a 10 sec shorter cycle
73 private const int SERVER_EQ_TIME_NO_EVENTS = VIEWER_TIMEOUT - (10 * 1000);
74
68 protected Scene m_scene; 75 protected Scene m_scene;
69 76
70 private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>(); 77 private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>();
@@ -84,7 +91,6 @@ namespace OpenSim.Region.ClientStack.Linden
84 scene.RegisterModuleInterface<IEventQueue>(this); 91 scene.RegisterModuleInterface<IEventQueue>(this);
85 92
86 scene.EventManager.OnClientClosed += ClientClosed; 93 scene.EventManager.OnClientClosed += ClientClosed;
87 scene.EventManager.OnMakeChildAgent += MakeChildAgent;
88 scene.EventManager.OnRegisterCaps += OnRegisterCaps; 94 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
89 95
90 MainConsole.Instance.Commands.AddCommand( 96 MainConsole.Instance.Commands.AddCommand(
@@ -113,7 +119,6 @@ namespace OpenSim.Region.ClientStack.Linden
113 return; 119 return;
114 120
115 scene.EventManager.OnClientClosed -= ClientClosed; 121 scene.EventManager.OnClientClosed -= ClientClosed;
116 scene.EventManager.OnMakeChildAgent -= MakeChildAgent;
117 scene.EventManager.OnRegisterCaps -= OnRegisterCaps; 122 scene.EventManager.OnRegisterCaps -= OnRegisterCaps;
118 123
119 scene.UnregisterModuleInterface<IEventQueue>(this); 124 scene.UnregisterModuleInterface<IEventQueue>(this);
@@ -182,14 +187,12 @@ namespace OpenSim.Region.ClientStack.Linden
182 { 187 {
183 if (!queues.ContainsKey(agentId)) 188 if (!queues.ContainsKey(agentId))
184 { 189 {
185 /*
186 m_log.DebugFormat( 190 m_log.DebugFormat(
187 "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}", 191 "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}",
188 agentId, m_scene.RegionInfo.RegionName); 192 agentId, m_scene.RegionInfo.RegionName);
189 */
190 queues[agentId] = new Queue<OSD>(); 193 queues[agentId] = new Queue<OSD>();
191 } 194 }
192 195
193 return queues[agentId]; 196 return queues[agentId];
194 } 197 }
195 } 198 }
@@ -221,8 +224,17 @@ namespace OpenSim.Region.ClientStack.Linden
221 { 224 {
222 Queue<OSD> queue = GetQueue(avatarID); 225 Queue<OSD> queue = GetQueue(avatarID);
223 if (queue != null) 226 if (queue != null)
227 {
224 lock (queue) 228 lock (queue)
225 queue.Enqueue(ev); 229 queue.Enqueue(ev);
230 }
231 else
232 {
233 OSDMap evMap = (OSDMap)ev;
234 m_log.WarnFormat(
235 "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} when placing message {1} in region {2}",
236 avatarID, evMap["message"], m_scene.Name);
237 }
226 } 238 }
227 catch (NullReferenceException e) 239 catch (NullReferenceException e)
228 { 240 {
@@ -237,44 +249,14 @@ namespace OpenSim.Region.ClientStack.Linden
237 249
238 private void ClientClosed(UUID agentID, Scene scene) 250 private void ClientClosed(UUID agentID, Scene scene)
239 { 251 {
240// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); 252 //m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
241
242 int count = 0;
243 while (queues.ContainsKey(agentID) && queues[agentID].Count > 0 && count++ < 5)
244 {
245 Thread.Sleep(1000);
246 }
247 253
248 lock (queues) 254 lock (queues)
249 {
250 queues.Remove(agentID); 255 queues.Remove(agentID);
251 }
252 256
253 List<UUID> removeitems = new List<UUID>(); 257 List<UUID> removeitems = new List<UUID>();
254 lock (m_AvatarQueueUUIDMapping) 258 lock (m_AvatarQueueUUIDMapping)
255 { 259 m_AvatarQueueUUIDMapping.Remove(agentID);
256 foreach (UUID ky in m_AvatarQueueUUIDMapping.Keys)
257 {
258// m_log.DebugFormat("[EVENTQUEUE]: Found key {0} in m_AvatarQueueUUIDMapping while looking for {1}", ky, AgentID);
259 if (ky == agentID)
260 {
261 removeitems.Add(ky);
262 }
263 }
264
265 foreach (UUID ky in removeitems)
266 {
267 UUID eventQueueGetUuid = m_AvatarQueueUUIDMapping[ky];
268 m_AvatarQueueUUIDMapping.Remove(ky);
269
270 string eqgPath = GenerateEqgCapPath(eventQueueGetUuid);
271 MainServer.Instance.RemovePollServiceHTTPHandler("", eqgPath);
272
273// m_log.DebugFormat(
274// "[EVENT QUEUE GET MODULE]: Removed EQG handler {0} for {1} in {2}",
275// eqgPath, agentID, m_scene.RegionInfo.RegionName);
276 }
277 }
278 260
279 UUID searchval = UUID.Zero; 261 UUID searchval = UUID.Zero;
280 262
@@ -295,19 +277,9 @@ namespace OpenSim.Region.ClientStack.Linden
295 foreach (UUID ky in removeitems) 277 foreach (UUID ky in removeitems)
296 m_QueueUUIDAvatarMapping.Remove(ky); 278 m_QueueUUIDAvatarMapping.Remove(ky);
297 } 279 }
298 }
299 280
300 private void MakeChildAgent(ScenePresence avatar) 281 // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
301 { 282
302 //m_log.DebugFormat("[EVENTQUEUE]: Make Child agent {0} in region {1}.", avatar.UUID, m_scene.RegionInfo.RegionName);
303 //lock (m_ids)
304 // {
305 //if (m_ids.ContainsKey(avatar.UUID))
306 //{
307 // close the event queue.
308 //m_ids[avatar.UUID] = -1;
309 //}
310 //}
311 } 283 }
312 284
313 /// <summary> 285 /// <summary>
@@ -323,9 +295,9 @@ namespace OpenSim.Region.ClientStack.Linden
323 { 295 {
324 // Register an event queue for the client 296 // Register an event queue for the client
325 297
326 //m_log.DebugFormat( 298 m_log.DebugFormat(
327 // "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", 299 "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}",
328 // agentID, caps, m_scene.RegionInfo.RegionName); 300 agentID, caps, m_scene.RegionInfo.RegionName);
329 301
330 // Let's instantiate a Queue for this agent right now 302 // Let's instantiate a Queue for this agent right now
331 TryGetQueue(agentID); 303 TryGetQueue(agentID);
@@ -359,28 +331,9 @@ namespace OpenSim.Region.ClientStack.Linden
359 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); 331 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
360 } 332 }
361 333
362 string eventQueueGetPath = GenerateEqgCapPath(eventQueueGetUUID); 334 caps.RegisterPollHandler(
363 335 "EventQueueGet",
364 // Register this as a caps handler 336 new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS));
365 // FIXME: Confusingly, we need to register separate as a capability so that the client is told about
366 // EventQueueGet when it receive capability information, but then we replace the rest handler immediately
367 // afterwards with the poll service. So for now, we'll pass a null instead to simplify code reading, but
368 // really it should be possible to directly register the poll handler as a capability.
369 caps.RegisterHandler("EventQueueGet", new RestHTTPHandler("POST", eventQueueGetPath, null));
370// delegate(Hashtable m_dhttpMethod)
371// {
372// return ProcessQueue(m_dhttpMethod, agentID, caps);
373// }));
374
375 // This will persist this beyond the expiry of the caps handlers
376 // TODO: Add EventQueueGet name/description for diagnostics
377 MainServer.Instance.AddPollServiceHTTPHandler(
378 eventQueueGetPath,
379 new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID, 40000));
380
381// m_log.DebugFormat(
382// "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}",
383// eventQueueGetPath, agentID, m_scene.RegionInfo.RegionName);
384 337
385 Random rnd = new Random(Environment.TickCount); 338 Random rnd = new Random(Environment.TickCount);
386 lock (m_ids) 339 lock (m_ids)
@@ -398,7 +351,10 @@ namespace OpenSim.Region.ClientStack.Linden
398 Queue<OSD> queue = GetQueue(agentID); 351 Queue<OSD> queue = GetQueue(agentID);
399 if (queue != null) 352 if (queue != null)
400 lock (queue) 353 lock (queue)
354 {
355 //m_log.WarnFormat("POLLED FOR EVENTS BY {0} in {1} -- {2}", agentID, m_scene.RegionInfo.RegionName, queue.Count);
401 return queue.Count > 0; 356 return queue.Count > 0;
357 }
402 358
403 return false; 359 return false;
404 } 360 }
@@ -414,16 +370,21 @@ namespace OpenSim.Region.ClientStack.Linden
414 OSDMap ev = (OSDMap)element; 370 OSDMap ev = (OSDMap)element;
415 m_log.DebugFormat( 371 m_log.DebugFormat(
416 "Eq OUT {0,-30} to {1,-20} {2,-20}", 372 "Eq OUT {0,-30} to {1,-20} {2,-20}",
417 ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.RegionInfo.RegionName); 373 ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.Name);
418 } 374 }
419 } 375 }
420 376
421 public Hashtable GetEvents(UUID requestID, UUID pAgentId) 377 public Hashtable GetEvents(UUID requestID, UUID pAgentId)
422 { 378 {
423 if (DebugLevel >= 2) 379 if (DebugLevel >= 2)
424 m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); 380 m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.Name);
381
382 Queue<OSD> queue = GetQueue(pAgentId);
383 if (queue == null)
384 {
385 return NoEvents(requestID, pAgentId);
386 }
425 387
426 Queue<OSD> queue = TryGetQueue(pAgentId);
427 OSD element; 388 OSD element;
428 lock (queue) 389 lock (queue)
429 { 390 {
@@ -750,34 +711,46 @@ namespace OpenSim.Region.ClientStack.Linden
750 Enqueue(item, avatarID); 711 Enqueue(item, avatarID);
751 } 712 }
752 713
753 public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID) 714 public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY)
754 { 715 {
755 OSD item = EventQueueHelper.EnableSimulator(handle, endPoint); 716 m_log.DebugFormat("{0} EnableSimulator. handle={1}, avatarID={2}, regionSize={3},{4}>",
717 "[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY);
718
719 OSD item = EventQueueHelper.EnableSimulator(handle, endPoint, regionSizeX, regionSizeY);
756 Enqueue(item, avatarID); 720 Enqueue(item, avatarID);
757 } 721 }
758 722
759 public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath) 723 public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath,
724 ulong regionHandle, int regionSizeX, int regionSizeY)
760 { 725 {
761 OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath); 726 m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, avatarID={2}, regionSize={3},{4}>",
727 "[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY);
728 OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath, regionHandle, regionSizeX, regionSizeY);
762 Enqueue(item, avatarID); 729 Enqueue(item, avatarID);
763 } 730 }
764 731
765 public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, 732 public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess,
766 IPEndPoint regionExternalEndPoint, 733 IPEndPoint regionExternalEndPoint,
767 uint locationID, uint flags, string capsURL, 734 uint locationID, uint flags, string capsURL,
768 UUID avatarID) 735 UUID avatarID, int regionSizeX, int regionSizeY)
769 { 736 {
737 m_log.DebugFormat("{0} TeleportFinishEvent. handle={1}, avatarID={2}, regionSize={3},{4}>",
738 "[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY);
739
770 OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint, 740 OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint,
771 locationID, flags, capsURL, avatarID); 741 locationID, flags, capsURL, avatarID, regionSizeX, regionSizeY);
772 Enqueue(item, avatarID); 742 Enqueue(item, avatarID);
773 } 743 }
774 744
775 public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, 745 public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
776 IPEndPoint newRegionExternalEndPoint, 746 IPEndPoint newRegionExternalEndPoint,
777 string capsURL, UUID avatarID, UUID sessionID) 747 string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY)
778 { 748 {
749 m_log.DebugFormat("{0} CrossRegion. handle={1}, avatarID={2}, regionSize={3},{4}>",
750 "[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY);
751
779 OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint, 752 OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint,
780 capsURL, avatarID, sessionID); 753 capsURL, avatarID, sessionID, regionSizeX, regionSizeY);
781 Enqueue(item, avatarID); 754 Enqueue(item, avatarID);
782 } 755 }
783 756
@@ -794,12 +767,12 @@ namespace OpenSim.Region.ClientStack.Linden
794 767
795 } 768 }
796 769
797 public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, 770 public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat,
798 bool isModerator, bool textMute) 771 bool isModerator, bool textMute)
799 { 772 {
800 OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, 773 OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat,
801 isModerator, textMute); 774 isModerator, textMute);
802 Enqueue(item, toAgent); 775 Enqueue(item, fromAgent);
803 //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); 776 //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item);
804 } 777 }
805 778
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
index 7dcf137..3fb7de2 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
@@ -70,13 +70,15 @@ namespace OpenSim.Region.ClientStack.Linden
70 return llsdEvent; 70 return llsdEvent;
71 } 71 }
72 72
73 public static OSD EnableSimulator(ulong handle, IPEndPoint endPoint) 73 public static OSD EnableSimulator(ulong handle, IPEndPoint endPoint, int regionSizeX, int regionSizeY)
74 { 74 {
75 OSDMap llsdSimInfo = new OSDMap(3); 75 OSDMap llsdSimInfo = new OSDMap(5);
76 76
77 llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle))); 77 llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle)));
78 llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes())); 78 llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes()));
79 llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port)); 79 llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port));
80 llsdSimInfo.Add("RegionSizeX", new OSDInteger(regionSizeX));
81 llsdSimInfo.Add("RegionSizeY", new OSDInteger(regionSizeY));
80 82
81 OSDArray arr = new OSDArray(1); 83 OSDArray arr = new OSDArray(1);
82 arr.Add(llsdSimInfo); 84 arr.Add(llsdSimInfo);
@@ -104,7 +106,8 @@ namespace OpenSim.Region.ClientStack.Linden
104 106
105 public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, 107 public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
106 IPEndPoint newRegionExternalEndPoint, 108 IPEndPoint newRegionExternalEndPoint,
107 string capsURL, UUID agentID, UUID sessionID) 109 string capsURL, UUID agentID, UUID sessionID,
110 int regionSizeX, int regionSizeY)
108 { 111 {
109 OSDArray lookAtArr = new OSDArray(3); 112 OSDArray lookAtArr = new OSDArray(3);
110 lookAtArr.Add(OSD.FromReal(lookAt.X)); 113 lookAtArr.Add(OSD.FromReal(lookAt.X));
@@ -130,11 +133,13 @@ namespace OpenSim.Region.ClientStack.Linden
130 OSDArray agentDataArr = new OSDArray(1); 133 OSDArray agentDataArr = new OSDArray(1);
131 agentDataArr.Add(agentDataMap); 134 agentDataArr.Add(agentDataMap);
132 135
133 OSDMap regionDataMap = new OSDMap(4); 136 OSDMap regionDataMap = new OSDMap(6);
134 regionDataMap.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(handle))); 137 regionDataMap.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(handle)));
135 regionDataMap.Add("SeedCapability", OSD.FromString(capsURL)); 138 regionDataMap.Add("SeedCapability", OSD.FromString(capsURL));
136 regionDataMap.Add("SimIP", OSD.FromBinary(newRegionExternalEndPoint.Address.GetAddressBytes())); 139 regionDataMap.Add("SimIP", OSD.FromBinary(newRegionExternalEndPoint.Address.GetAddressBytes()));
137 regionDataMap.Add("SimPort", OSD.FromInteger(newRegionExternalEndPoint.Port)); 140 regionDataMap.Add("SimPort", OSD.FromInteger(newRegionExternalEndPoint.Port));
141 regionDataMap.Add("RegionSizeX", new OSDInteger(regionSizeX));
142 regionDataMap.Add("RegionSizeY", new OSDInteger(regionSizeY));
138 143
139 OSDArray regionDataArr = new OSDArray(1); 144 OSDArray regionDataArr = new OSDArray(1);
140 regionDataArr.Add(regionDataMap); 145 regionDataArr.Add(regionDataMap);
@@ -148,8 +153,9 @@ namespace OpenSim.Region.ClientStack.Linden
148 } 153 }
149 154
150 public static OSD TeleportFinishEvent( 155 public static OSD TeleportFinishEvent(
151 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, 156 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
152 uint locationID, uint flags, string capsURL, UUID agentID) 157 uint locationID, uint flags, string capsURL, UUID agentID,
158 int regionSizeX, int regionSizeY)
153 { 159 {
154 // not sure why flags get overwritten here 160 // not sure why flags get overwritten here
155 if ((flags & (uint)TeleportFlags.IsFlying) != 0) 161 if ((flags & (uint)TeleportFlags.IsFlying) != 0)
@@ -167,6 +173,8 @@ namespace OpenSim.Region.ClientStack.Linden
167 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port)); 173 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port));
168// info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation 174// info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation
169 info.Add("TeleportFlags", OSD.FromUInteger(flags)); 175 info.Add("TeleportFlags", OSD.FromUInteger(flags));
176 info.Add("RegionSizeX", new OSDInteger(regionSizeX));
177 info.Add("RegionSizeY", new OSDInteger(regionSizeY));
170 178
171 OSDArray infoArr = new OSDArray(); 179 OSDArray infoArr = new OSDArray();
172 infoArr.Add(info); 180 infoArr.Add(info);
@@ -194,12 +202,18 @@ namespace OpenSim.Region.ClientStack.Linden
194 return BuildEvent("ScriptRunningReply", body); 202 return BuildEvent("ScriptRunningReply", body);
195 } 203 }
196 204
197 public static OSD EstablishAgentCommunication(UUID agentID, string simIpAndPort, string seedcap) 205 public static OSD EstablishAgentCommunication(UUID agentID, string simIpAndPort, string seedcap,
206 ulong regionHandle, int regionSizeX, int regionSizeY)
198 { 207 {
199 OSDMap body = new OSDMap(3); 208 OSDMap body = new OSDMap(6)
200 body.Add("agent-id", new OSDUUID(agentID)); 209 {
201 body.Add("sim-ip-and-port", new OSDString(simIpAndPort)); 210 {"agent-id", new OSDUUID(agentID)},
202 body.Add("seed-capability", new OSDString(seedcap)); 211 {"sim-ip-and-port", new OSDString(simIpAndPort)},
212 {"seed-capability", new OSDString(seedcap)},
213 {"region-handle", OSD.FromULong(regionHandle)},
214 {"region-size-x", OSD.FromInteger(regionSizeX)},
215 {"region-size-y", OSD.FromInteger(regionSizeY)}
216 };
203 217
204 return BuildEvent("EstablishAgentCommunication", body); 218 return BuildEvent("EstablishAgentCommunication", body);
205 } 219 }
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
index 141af8a..9e24bce 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
@@ -76,7 +76,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
76 } 76 }
77 77
78 [Test] 78 [Test]
79 public void AddForClient() 79 public void TestAddForClient()
80 { 80 {
81 TestHelpers.InMethod(); 81 TestHelpers.InMethod();
82// log4net.Config.XmlConfigurator.Configure(); 82// log4net.Config.XmlConfigurator.Configure();
@@ -88,15 +88,15 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
88 } 88 }
89 89
90 [Test] 90 [Test]
91 public void RemoveForClient() 91 public void TestRemoveForClient()
92 { 92 {
93 TestHelpers.InMethod(); 93 TestHelpers.InMethod();
94// log4net.Config.XmlConfigurator.Configure(); 94// TestHelpers.EnableLogging();
95 95
96 UUID spId = TestHelpers.ParseTail(0x1); 96 UUID spId = TestHelpers.ParseTail(0x1);
97 97
98 SceneHelpers.AddScenePresence(m_scene, spId); 98 SceneHelpers.AddScenePresence(m_scene, spId);
99 m_scene.IncomingCloseAgent(spId, false); 99 m_scene.CloseAgent(spId, false);
100 100
101 // TODO: Add more assertions for the other aspects of event queues 101 // TODO: Add more assertions for the other aspects of event queues
102 Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0)); 102 Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0));
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
index 6ec1115..7b15284 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
@@ -246,8 +246,8 @@ namespace OpenSim.Region.ClientStack.Linden
246 246
247 private Scene m_scene; 247 private Scene m_scene;
248 private MeshCapsDataThrottler m_throttler; 248 private MeshCapsDataThrottler m_throttler;
249 public PollServiceMeshEventArgs(UUID pId, Scene scene) : 249 public PollServiceMeshEventArgs(string uri, UUID pId, Scene scene) :
250 base(null, null, null, null, pId, int.MaxValue) 250 base(null, uri, null, null, null, pId, int.MaxValue)
251 { 251 {
252 m_scene = scene; 252 m_scene = scene;
253 m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene, pId); 253 m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene, pId);
@@ -361,7 +361,7 @@ namespace OpenSim.Region.ClientStack.Linden
361 string capUrl = "/CAPS/" + UUID.Random() + "/"; 361 string capUrl = "/CAPS/" + UUID.Random() + "/";
362 362
363 // Register this as a poll service 363 // Register this as a poll service
364 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(agentID, m_scene); 364 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(capUrl, agentID, m_scene);
365 365
366 args.Type = PollServiceEventArgs.EventType.Mesh; 366 args.Type = PollServiceEventArgs.EventType.Mesh;
367 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); 367 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
index 0570144..e053054 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
@@ -84,6 +84,8 @@ namespace OpenSim.Region.ClientStack.Linden
84 84
85 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>(); 85 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>();
86 86
87 private string m_URL;
88
87 #region ISharedRegionModule Members 89 #region ISharedRegionModule Members
88 90
89 public void Initialise(IConfigSource source) 91 public void Initialise(IConfigSource source)
@@ -215,7 +217,7 @@ namespace OpenSim.Region.ClientStack.Linden
215 private Scene m_scene; 217 private Scene m_scene;
216 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000); 218 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000);
217 public PollServiceTextureEventArgs(UUID pId, Scene scene) : 219 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
218 base(null, null, null, null, pId, int.MaxValue) 220 base(null, "", null, null, null, pId, int.MaxValue)
219 { 221 {
220 m_scene = scene; 222 m_scene = scene;
221 // x is request id, y is userid 223 // x is request id, y is userid
@@ -368,7 +370,11 @@ namespace OpenSim.Region.ClientStack.Linden
368 port = MainServer.Instance.SSLPort; 370 port = MainServer.Instance.SSLPort;
369 protocol = "https"; 371 protocol = "https";
370 } 372 }
371 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); 373 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
374 if (handler != null)
375 handler.RegisterExternalUserCapsHandler(agentID, caps, "GetTexture", capUrl);
376 else
377 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
372 m_pollservices[agentID] = args; 378 m_pollservices[agentID] = args;
373 m_capsDict[agentID] = capUrl; 379 m_capsDict[agentID] = capUrl;
374 } 380 }
@@ -380,13 +386,11 @@ namespace OpenSim.Region.ClientStack.Linden
380 386
381 private void DeregisterCaps(UUID agentID, Caps caps) 387 private void DeregisterCaps(UUID agentID, Caps caps)
382 { 388 {
383 string capUrl;
384 PollServiceTextureEventArgs args; 389 PollServiceTextureEventArgs args;
385 if (m_capsDict.TryGetValue(agentID, out capUrl)) 390
386 { 391 MainServer.Instance.RemoveHTTPHandler("", m_URL);
387 MainServer.Instance.RemoveHTTPHandler("", capUrl); 392 m_capsDict.Remove(agentID);
388 m_capsDict.Remove(agentID); 393
389 }
390 if (m_pollservices.TryGetValue(agentID, out args)) 394 if (m_pollservices.TryGetValue(agentID, out args))
391 { 395 {
392 m_pollservices.Remove(agentID); 396 m_pollservices.Remove(agentID);
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs
index 92805e2..94f8bc1 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs
@@ -155,6 +155,7 @@ namespace OpenSim.Region.ClientStack.Linden
155 Quaternion rotation = Quaternion.Identity; 155 Quaternion rotation = Quaternion.Identity;
156 Vector3 scale = Vector3.Zero; 156 Vector3 scale = Vector3.Zero;
157 int state = 0; 157 int state = 0;
158 int lastattach = 0;
158 159
159 if (r.Type != OSDType.Map) // not a proper req 160 if (r.Type != OSDType.Map) // not a proper req
160 return responsedata; 161 return responsedata;
@@ -224,6 +225,7 @@ namespace OpenSim.Region.ClientStack.Linden
224 225
225 ray_target_id = ObjMap["RayTargetId"].AsUUID(); 226 ray_target_id = ObjMap["RayTargetId"].AsUUID();
226 state = ObjMap["State"].AsInteger(); 227 state = ObjMap["State"].AsInteger();
228 lastattach = ObjMap["LastAttachPoint"].AsInteger();
227 try 229 try
228 { 230 {
229 ray_end = ((OSDArray)ObjMap["RayEnd"]).AsVector3(); 231 ray_end = ((OSDArray)ObjMap["RayEnd"]).AsVector3();
@@ -290,6 +292,7 @@ namespace OpenSim.Region.ClientStack.Linden
290 292
291 //session_id = rm["session_id"].AsUUID(); 293 //session_id = rm["session_id"].AsUUID();
292 state = rm["state"].AsInteger(); 294 state = rm["state"].AsInteger();
295 lastattach = rm["last_attach_point"].AsInteger();
293 try 296 try
294 { 297 {
295 ray_end = ((OSDArray)rm["ray_end"]).AsVector3(); 298 ray_end = ((OSDArray)rm["ray_end"]).AsVector3();
@@ -331,6 +334,7 @@ namespace OpenSim.Region.ClientStack.Linden
331 pbs.ProfileEnd = (ushort)profile_end; 334 pbs.ProfileEnd = (ushort)profile_end;
332 pbs.Scale = scale; 335 pbs.Scale = scale;
333 pbs.State = (byte)state; 336 pbs.State = (byte)state;
337 pbs.LastAttachPoint = (byte)lastattach;
334 338
335 SceneObjectGroup obj = null; ; 339 SceneObjectGroup obj = null; ;
336 340
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
index 55a503e..769fe28 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
@@ -277,6 +277,7 @@ namespace OpenSim.Region.ClientStack.Linden
277 pbs.ProfileEnd = (ushort) obj.ProfileEnd; 277 pbs.ProfileEnd = (ushort) obj.ProfileEnd;
278 pbs.Scale = obj.Scale; 278 pbs.Scale = obj.Scale;
279 pbs.State = (byte) 0; 279 pbs.State = (byte) 0;
280 pbs.LastAttachPoint = (byte) 0;
280 SceneObjectPart prim = new SceneObjectPart(); 281 SceneObjectPart prim = new SceneObjectPart();
281 prim.UUID = UUID.Random(); 282 prim.UUID = UUID.Random();
282 prim.CreatorID = AgentId; 283 prim.CreatorID = AgentId;
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs
index 595d01a..112608b 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.6.*")] 32[assembly: AssemblyVersion("0.8.0.*")]
33 33
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
index 79d56c4..5196368 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
@@ -183,7 +183,7 @@ namespace OpenSim.Region.ClientStack.Linden
183 m_isGod = m_scene.Permissions.IsGod(agentID); 183 m_isGod = m_scene.Permissions.IsGod(agentID);
184 } 184 }
185 185
186 public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 186 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
187 { 187 {
188 StreamReader reader = new StreamReader(request); 188 StreamReader reader = new StreamReader(request);
189 string message = reader.ReadToEnd(); 189 string message = reader.ReadToEnd();
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
index 7d9f935..e4d8a20 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
@@ -68,7 +68,6 @@ namespace OpenSim.Region.ClientStack.Linden
68 /// </summary> 68 /// </summary>
69 private OSDMap m_features = new OSDMap(); 69 private OSDMap m_features = new OSDMap();
70 70
71 private string m_MapImageServerURL = string.Empty;
72 private string m_SearchURL = string.Empty; 71 private string m_SearchURL = string.Empty;
73 private bool m_ExportSupported = false; 72 private bool m_ExportSupported = false;
74 73
@@ -78,15 +77,7 @@ namespace OpenSim.Region.ClientStack.Linden
78 { 77 {
79 IConfig config = source.Configs["SimulatorFeatures"]; 78 IConfig config = source.Configs["SimulatorFeatures"];
80 if (config != null) 79 if (config != null)
81 { 80 {
82 m_MapImageServerURL = config.GetString("MapImageServerURI", string.Empty);
83 if (m_MapImageServerURL != string.Empty)
84 {
85 m_MapImageServerURL = m_MapImageServerURL.Trim();
86 if (!m_MapImageServerURL.EndsWith("/"))
87 m_MapImageServerURL = m_MapImageServerURL + "/";
88 }
89
90 m_SearchURL = config.GetString("SearchServerURI", string.Empty); 81 m_SearchURL = config.GetString("SearchServerURI", string.Empty);
91 82
92 m_ExportSupported = config.GetBoolean("ExportSupported", m_ExportSupported); 83 m_ExportSupported = config.GetBoolean("ExportSupported", m_ExportSupported);
@@ -149,15 +140,16 @@ namespace OpenSim.Region.ClientStack.Linden
149 m_features["PhysicsShapeTypes"] = typesMap; 140 m_features["PhysicsShapeTypes"] = typesMap;
150 141
151 // Extra information for viewers that want to use it 142 // Extra information for viewers that want to use it
152 OSDMap gridServicesMap = new OSDMap(); 143 // TODO: Take these out of here into their respective modules, like map-server-url
153 if (m_MapImageServerURL != string.Empty) 144 OSDMap extrasMap = new OSDMap();
154 gridServicesMap["map-server-url"] = m_MapImageServerURL;
155 if (m_SearchURL != string.Empty) 145 if (m_SearchURL != string.Empty)
156 gridServicesMap["search"] = m_SearchURL; 146 extrasMap["search-server-url"] = m_SearchURL;
157 m_features["GridServices"] = gridServicesMap;
158
159 if (m_ExportSupported) 147 if (m_ExportSupported)
160 m_features["ExportSupported"] = true; 148 extrasMap["ExportSupported"] = true;
149
150 if (extrasMap.Count > 0)
151 m_features["OpenSimExtras"] = extrasMap;
152
161 } 153 }
162 } 154 }
163 155
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
index eca576d..47988dd 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
@@ -64,11 +64,18 @@ namespace OpenSim.Region.ClientStack.Linden
64 64
65 private Scene m_scene; 65 private Scene m_scene;
66 private bool m_persistBakedTextures; 66 private bool m_persistBakedTextures;
67 private string m_URL;
67 68
68 private IBakedTextureModule m_BakedTextureModule; 69 private IBakedTextureModule m_BakedTextureModule;
69 70
70 public void Initialise(IConfigSource source) 71 public void Initialise(IConfigSource source)
71 { 72 {
73 IConfig config = source.Configs["ClientStack.LindenCaps"];
74 if (config == null)
75 return;
76
77 m_URL = config.GetString("Cap_UploadBakedTexture", string.Empty);
78
72 IConfig appearanceConfig = source.Configs["Appearance"]; 79 IConfig appearanceConfig = source.Configs["Appearance"];
73 if (appearanceConfig != null) 80 if (appearanceConfig != null)
74 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 81 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
@@ -280,23 +287,28 @@ namespace OpenSim.Region.ClientStack.Linden
280 287
281 public void RegisterCaps(UUID agentID, Caps caps) 288 public void RegisterCaps(UUID agentID, Caps caps)
282 { 289 {
283 UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler( 290// UUID capID = UUID.Random();
284 caps, m_scene.AssetService, m_persistBakedTextures);
285 291
286 292 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
287 293 if (m_URL == "localhost")
288 caps.RegisterHandler( 294 {
289 "UploadBakedTexture", 295 UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler(
290 new RestStreamHandler( 296 caps, m_scene.AssetService, m_persistBakedTextures);
291 "POST",
292 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
293 avatarhandler.UploadBakedTexture,
294 "UploadBakedTexture",
295 agentID.ToString()));
296
297
298
299 297
298 caps.RegisterHandler(
299 "UploadBakedTexture",
300 new RestStreamHandler(
301 "POST",
302 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
303 avatarhandler.UploadBakedTexture,
304 "UploadBakedTexture",
305 agentID.ToString()));
306
307 }
308 else
309 {
310 caps.RegisterHandler("UploadBakedTexture", m_URL);
311 }
300 } 312 }
301 } 313 }
302} \ No newline at end of file 314}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
index 707cc93..6fc35cd 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
@@ -71,9 +71,13 @@ namespace OpenSim.Region.ClientStack.Linden
71 private IInventoryService m_InventoryService; 71 private IInventoryService m_InventoryService;
72 private ILibraryService m_LibraryService; 72 private ILibraryService m_LibraryService;
73 73
74 private bool m_Enabled;
75
76 private string m_fetchInventoryDescendents2Url;
77 private string m_webFetchInventoryDescendentsUrl;
78
74 private static WebFetchInvDescHandler m_webFetchHandler; 79 private static WebFetchInvDescHandler m_webFetchHandler;
75 80
76 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
77 private static Thread[] m_workerThreads = null; 81 private static Thread[] m_workerThreads = null;
78 82
79 private static DoubleQueue<aPollRequest> m_queue = 83 private static DoubleQueue<aPollRequest> m_queue =
@@ -83,22 +87,45 @@ namespace OpenSim.Region.ClientStack.Linden
83 87
84 public void Initialise(IConfigSource source) 88 public void Initialise(IConfigSource source)
85 { 89 {
90 IConfig config = source.Configs["ClientStack.LindenCaps"];
91 if (config == null)
92 return;
93
94 m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty);
95 m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty);
96
97 if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty)
98 {
99 m_Enabled = true;
100 }
86 } 101 }
87 102
88 public void AddRegion(Scene s) 103 public void AddRegion(Scene s)
89 { 104 {
105 if (!m_Enabled)
106 return;
107
90 m_scene = s; 108 m_scene = s;
91 } 109 }
92 110
93 public void RemoveRegion(Scene s) 111 public void RemoveRegion(Scene s)
94 { 112 {
113 if (!m_Enabled)
114 return;
115
95 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 116 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
96 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; 117
118 foreach (Thread t in m_workerThreads)
119 Watchdog.AbortThread(t.ManagedThreadId);
120
97 m_scene = null; 121 m_scene = null;
98 } 122 }
99 123
100 public void RegionLoaded(Scene s) 124 public void RegionLoaded(Scene s)
101 { 125 {
126 if (!m_Enabled)
127 return;
128
102 m_InventoryService = m_scene.InventoryService; 129 m_InventoryService = m_scene.InventoryService;
103 m_LibraryService = m_scene.LibraryService; 130 m_LibraryService = m_scene.LibraryService;
104 131
@@ -106,7 +133,6 @@ namespace OpenSim.Region.ClientStack.Linden
106 m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService); 133 m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
107 134
108 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 135 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
109 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
110 136
111 if (m_workerThreads == null) 137 if (m_workerThreads == null)
112 { 138 {
@@ -140,12 +166,6 @@ namespace OpenSim.Region.ClientStack.Linden
140 166
141 #endregion 167 #endregion
142 168
143 ~WebFetchInvDescModule()
144 {
145 foreach (Thread t in m_workerThreads)
146 Watchdog.AbortThread(t.ManagedThreadId);
147 }
148
149 private class PollServiceInventoryEventArgs : PollServiceEventArgs 169 private class PollServiceInventoryEventArgs : PollServiceEventArgs
150 { 170 {
151 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 171 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -155,8 +175,8 @@ namespace OpenSim.Region.ClientStack.Linden
155 175
156 private Scene m_scene; 176 private Scene m_scene;
157 177
158 public PollServiceInventoryEventArgs(Scene scene, UUID pId) : 178 public PollServiceInventoryEventArgs(Scene scene, string url, UUID pId) :
159 base(null, null, null, null, pId, int.MaxValue) 179 base(null, url, null, null, null, pId, int.MaxValue)
160 { 180 {
161 m_scene = scene; 181 m_scene = scene;
162 182
@@ -278,53 +298,72 @@ namespace OpenSim.Region.ClientStack.Linden
278 requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); 298 requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null);
279 299
280 lock (responses) 300 lock (responses)
281 responses[requestID] = response; 301 responses[requestID] = response;
282 } 302 }
283 } 303 }
284 304
285 private void RegisterCaps(UUID agentID, Caps caps) 305 private void RegisterCaps(UUID agentID, Caps caps)
286 { 306 {
287 string capUrl = "/CAPS/" + UUID.Random() + "/"; 307 RegisterFetchDescendentsCap(agentID, caps, "FetchInventoryDescendents2", m_fetchInventoryDescendents2Url);
288
289 // Register this as a poll service
290 PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID);
291
292 args.Type = PollServiceEventArgs.EventType.Inventory;
293 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
294
295 string hostName = m_scene.RegionInfo.ExternalHostName;
296 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
297 string protocol = "http";
298
299 if (MainServer.Instance.UseSSL)
300 {
301 hostName = MainServer.Instance.SSLCommonName;
302 port = MainServer.Instance.SSLPort;
303 protocol = "https";
304 }
305 caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
306
307 m_capsDict[agentID] = capUrl;
308 } 308 }
309 309
310 private void DeregisterCaps(UUID agentID, Caps caps) 310 private void RegisterFetchDescendentsCap(UUID agentID, Caps caps, string capName, string url)
311 { 311 {
312 string capUrl; 312 string capUrl;
313 313
314 if (m_capsDict.TryGetValue(agentID, out capUrl)) 314 // disable the cap clause
315 if (url == "")
316 {
317 return;
318 }
319 // handled by the simulator
320 else if (url == "localhost")
321 {
322 capUrl = "/CAPS/" + UUID.Random() + "/";
323
324 // Register this as a poll service
325 PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, capUrl, agentID);
326 args.Type = PollServiceEventArgs.EventType.Inventory;
327
328 caps.RegisterPollHandler(capName, args);
329 }
330 // external handler
331 else
315 { 332 {
316 MainServer.Instance.RemoveHTTPHandler("", capUrl); 333 capUrl = url;
317 m_capsDict.Remove(agentID); 334 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
335 if (handler != null)
336 handler.RegisterExternalUserCapsHandler(agentID,caps,capName,capUrl);
337 else
338 caps.RegisterHandler(capName, capUrl);
318 } 339 }
340
341 // m_log.DebugFormat(
342 // "[FETCH INVENTORY DESCENDENTS2 MODULE]: Registered capability {0} at {1} in region {2} for {3}",
343 // capName, capUrl, m_scene.RegionInfo.RegionName, agentID);
319 } 344 }
320 345
346// private void DeregisterCaps(UUID agentID, Caps caps)
347// {
348// string capUrl;
349//
350// if (m_capsDict.TryGetValue(agentID, out capUrl))
351// {
352// MainServer.Instance.RemoveHTTPHandler("", capUrl);
353// m_capsDict.Remove(agentID);
354// }
355// }
356
321 private void DoInventoryRequests() 357 private void DoInventoryRequests()
322 { 358 {
323 while (true) 359 while (true)
324 { 360 {
361 Watchdog.UpdateThread();
362
325 aPollRequest poolreq = m_queue.Dequeue(); 363 aPollRequest poolreq = m_queue.Dequeue();
326 364
327 poolreq.thepoll.Process(poolreq); 365 if (poolreq != null && poolreq.thepoll != null)
366 poolreq.thepoll.Process(poolreq);
328 } 367 }
329 } 368 }
330 } 369 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
index 3995620..15d6f7f 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
@@ -424,12 +424,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
424 // foreign user is visiting, we need to try again after the first fail to the local 424 // foreign user is visiting, we need to try again after the first fail to the local
425 // asset service. 425 // asset service.
426 string assetServerURL = string.Empty; 426 string assetServerURL = string.Empty;
427 if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL)) 427 if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL) && !string.IsNullOrEmpty(assetServerURL))
428 { 428 {
429 if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("=")) 429 if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("="))
430 assetServerURL = assetServerURL + "/"; 430 assetServerURL = assetServerURL + "/";
431 431
432 m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id); 432// m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id);
433 AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived); 433 AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived);
434 return; 434 return;
435 } 435 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 7c62f90..f599342 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -84,6 +84,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
84 public event ModifyTerrain OnModifyTerrain; 84 public event ModifyTerrain OnModifyTerrain;
85 public event Action<IClientAPI> OnRegionHandShakeReply; 85 public event Action<IClientAPI> OnRegionHandShakeReply;
86 public event GenericCall1 OnRequestWearables; 86 public event GenericCall1 OnRequestWearables;
87 public event CachedTextureRequest OnCachedTextureRequest;
87 public event SetAppearance OnSetAppearance; 88 public event SetAppearance OnSetAppearance;
88 public event AvatarNowWearing OnAvatarNowWearing; 89 public event AvatarNowWearing OnAvatarNowWearing;
89 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; 90 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv;
@@ -95,6 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
95 public event Action<IClientAPI, bool> OnCompleteMovementToRegion; 96 public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
96 public event UpdateAgent OnPreAgentUpdate; 97 public event UpdateAgent OnPreAgentUpdate;
97 public event UpdateAgent OnAgentUpdate; 98 public event UpdateAgent OnAgentUpdate;
99 public event UpdateAgent OnAgentCameraUpdate;
98 public event AgentRequestSit OnAgentRequestSit; 100 public event AgentRequestSit OnAgentRequestSit;
99 public event AgentSit OnAgentSit; 101 public event AgentSit OnAgentSit;
100 public event AvatarPickerRequest OnAvatarPickerRequest; 102 public event AvatarPickerRequest OnAvatarPickerRequest;
@@ -335,6 +337,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
335 private bool m_VelocityInterpolate = false; 337 private bool m_VelocityInterpolate = false;
336 private const uint MaxTransferBytesPerPacket = 600; 338 private const uint MaxTransferBytesPerPacket = 600;
337 339
340 private volatile bool m_justEditedTerrain = false;
338 341
339 /// <value> 342 /// <value>
340 /// List used in construction of data blocks for an object update packet. This is to stop us having to 343 /// List used in construction of data blocks for an object update packet. This is to stop us having to
@@ -367,7 +370,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
367 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods 370 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
368 /// cannot retain a reference to it outside of that method. 371 /// cannot retain a reference to it outside of that method.
369 /// </remarks> 372 /// </remarks>
370 private AgentUpdateArgs m_lastAgentUpdateArgs; 373 private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs();
371 374
372 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); 375 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
373 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers 376 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@@ -504,6 +507,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
504 m_udpServer = udpServer; 507 m_udpServer = udpServer;
505 m_udpClient = udpClient; 508 m_udpClient = udpClient;
506 m_udpClient.OnQueueEmpty += HandleQueueEmpty; 509 m_udpClient.OnQueueEmpty += HandleQueueEmpty;
510 m_udpClient.HasUpdates += HandleHasUpdates;
507 m_udpClient.OnPacketStats += PopulateStats; 511 m_udpClient.OnPacketStats += PopulateStats;
508 512
509 m_prioritizer = new Prioritizer(m_scene); 513 m_prioritizer = new Prioritizer(m_scene);
@@ -533,7 +537,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
533 // We still perform a force close inside the sync lock since this is intended to attempt close where 537 // We still perform a force close inside the sync lock since this is intended to attempt close where
534 // there is some unidentified connection problem, not where we have issues due to deadlock 538 // there is some unidentified connection problem, not where we have issues due to deadlock
535 if (!IsActive && !force) 539 if (!IsActive && !force)
540 {
541 m_log.DebugFormat(
542 "[CLIENT]: Not attempting to close inactive client {0} in {1} since force flag is not set",
543 Name, m_scene.Name);
544
536 return; 545 return;
546 }
537 547
538 IsActive = false; 548 IsActive = false;
539 CloseWithoutChecks(sendStop); 549 CloseWithoutChecks(sendStop);
@@ -709,12 +719,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
709 //there is a local handler for this packet type 719 //there is a local handler for this packet type
710 if (pprocessor.Async) 720 if (pprocessor.Async)
711 { 721 {
722 ClientInfo cinfo = UDPClient.GetClientInfo();
723 if (!cinfo.AsyncRequests.ContainsKey(packet.Type.ToString()))
724 cinfo.AsyncRequests[packet.Type.ToString()] = 0;
725 cinfo.AsyncRequests[packet.Type.ToString()]++;
726
712 object obj = new AsyncPacketProcess(this, pprocessor.method, packet); 727 object obj = new AsyncPacketProcess(this, pprocessor.method, packet);
713 Util.FireAndForget(ProcessSpecificPacketAsync, obj); 728 Util.FireAndForget(ProcessSpecificPacketAsync, obj);
714 result = true; 729 result = true;
715 } 730 }
716 else 731 else
717 { 732 {
733 ClientInfo cinfo = UDPClient.GetClientInfo();
734 if (!cinfo.SyncRequests.ContainsKey(packet.Type.ToString()))
735 cinfo.SyncRequests[packet.Type.ToString()] = 0;
736 cinfo.SyncRequests[packet.Type.ToString()]++;
737
718 result = pprocessor.method(this, packet); 738 result = pprocessor.method(this, packet);
719 } 739 }
720 } 740 }
@@ -729,6 +749,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
729 } 749 }
730 if (found) 750 if (found)
731 { 751 {
752 ClientInfo cinfo = UDPClient.GetClientInfo();
753 if (!cinfo.GenericRequests.ContainsKey(packet.Type.ToString()))
754 cinfo.GenericRequests[packet.Type.ToString()] = 0;
755 cinfo.GenericRequests[packet.Type.ToString()]++;
756
732 result = method(this, packet); 757 result = method(this, packet);
733 } 758 }
734 } 759 }
@@ -758,7 +783,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
758 783
759 public virtual void Start() 784 public virtual void Start()
760 { 785 {
761 m_scene.AddNewClient(this, PresenceType.User); 786 m_scene.AddNewAgent(this, PresenceType.User);
762 787
763 RefreshGroupMembership(); 788 RefreshGroupMembership();
764 } 789 }
@@ -820,12 +845,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
820 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); 845 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType);
821 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; 846 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes;
822 847
823 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0]; 848 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1];
824// OutPacket(handshake, ThrottleOutPacketType.Task); 849 handshake.RegionInfo4[0] = new RegionHandshakePacket.RegionInfo4Block();
825 // use same as MoveAgentIntoRegion (both should be task ) 850 handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags;
851 handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported
852
826 OutPacket(handshake, ThrottleOutPacketType.Unknown); 853 OutPacket(handshake, ThrottleOutPacketType.Unknown);
827 } 854 }
828 855
856
829 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) 857 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
830 { 858 {
831 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); 859 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete);
@@ -1210,9 +1238,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1210 LLHeightFieldMoronize(map); 1238 LLHeightFieldMoronize(map);
1211 1239
1212 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1240 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1213 layerpack.Header.Reliable = true; 1241
1242 // When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience.
1243 // To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain.
1244 // We also make them unreliable because it's extremely likely that multiple packets will be sent for a terrain patch area
1245 // invalidating previous packets for that area.
1246
1247 // It's possible for an editing user to flood themselves with edited packets but the majority of use cases are such that only a
1248 // tiny percentage of users will be editing the terrain. Other, non-editing users will see the edits much slower.
1249
1250 // One last note on this topic, by the time users are going to be editing the terrain, it's extremely likely that the sim will
1251 // have rezzed already and therefore this is not likely going to cause any additional issues with lost packets, objects or terrain
1252 // patches.
1214 1253
1215 OutPacket(layerpack, ThrottleOutPacketType.Task); 1254 // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we only have one cache miss.
1255 if (m_justEditedTerrain)
1256 {
1257 layerpack.Header.Reliable = false;
1258 OutPacket(layerpack,
1259 ThrottleOutPacketType.Unknown );
1260 }
1261 else
1262 {
1263 layerpack.Header.Reliable = true;
1264 OutPacket(layerpack,
1265 ThrottleOutPacketType.Task);
1266 }
1216 } 1267 }
1217 catch (Exception e) 1268 catch (Exception e)
1218 { 1269 {
@@ -1405,6 +1456,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1405 1456
1406 mapReply.AgentData.AgentID = AgentId; 1457 mapReply.AgentData.AgentID = AgentId;
1407 mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length]; 1458 mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length];
1459 mapReply.Size = new MapBlockReplyPacket.SizeBlock[mapBlocks2.Length];
1408 mapReply.AgentData.Flags = flag; 1460 mapReply.AgentData.Flags = flag;
1409 1461
1410 for (int i = 0; i < mapBlocks2.Length; i++) 1462 for (int i = 0; i < mapBlocks2.Length; i++)
@@ -1419,6 +1471,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1419 mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags; 1471 mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags;
1420 mapReply.Data[i].Access = mapBlocks2[i].Access; 1472 mapReply.Data[i].Access = mapBlocks2[i].Access;
1421 mapReply.Data[i].Agents = mapBlocks2[i].Agents; 1473 mapReply.Data[i].Agents = mapBlocks2[i].Agents;
1474
1475 // TODO: hookup varregion sim size here
1476 mapReply.Size[i] = new MapBlockReplyPacket.SizeBlock();
1477 mapReply.Size[i].SizeX = 256;
1478 mapReply.Size[i].SizeY = 256;
1422 } 1479 }
1423 OutPacket(mapReply, ThrottleOutPacketType.Land); 1480 OutPacket(mapReply, ThrottleOutPacketType.Land);
1424 } 1481 }
@@ -1580,7 +1637,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1580 OutPacket(pc, ThrottleOutPacketType.Unknown); 1637 OutPacket(pc, ThrottleOutPacketType.Unknown);
1581 } 1638 }
1582 1639
1583 public void SendKillObject(ulong regionHandle, List<uint> localIDs) 1640 public void SendKillObject(List<uint> localIDs)
1584 { 1641 {
1585// foreach (uint id in localIDs) 1642// foreach (uint id in localIDs)
1586// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); 1643// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
@@ -2594,11 +2651,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2594 { 2651 {
2595 AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket(); 2652 AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket();
2596 avatarSitResponse.SitObject.ID = TargetID; 2653 avatarSitResponse.SitObject.ID = TargetID;
2597 if (CameraAtOffset != Vector3.Zero) 2654 avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset;
2598 { 2655 avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset;
2599 avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset;
2600 avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset;
2601 }
2602 avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook; 2656 avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook;
2603 avatarSitResponse.SitTransform.AutoPilot = autopilot; 2657 avatarSitResponse.SitTransform.AutoPilot = autopilot;
2604 avatarSitResponse.SitTransform.SitPosition = OffsetPos; 2658 avatarSitResponse.SitTransform.SitPosition = OffsetPos;
@@ -3794,12 +3848,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3794 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber); 3848 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
3795 3849
3796 // Count this as a resent packet since we are going to requeue all of the updates contained in it 3850 // Count this as a resent packet since we are going to requeue all of the updates contained in it
3797 Interlocked.Increment(ref m_udpClient.PacketsResent); 3851 Interlocked.Increment(ref m_udpClient.PacketsResent);
3852
3853 // We're not going to worry about interlock yet since its not currently critical that this total count
3854 // is 100% correct
3855 m_udpServer.PacketsResentCount++;
3798 3856
3799 foreach (EntityUpdate update in updates) 3857 foreach (EntityUpdate update in updates)
3800 ResendPrimUpdate(update); 3858 ResendPrimUpdate(update);
3801 } 3859 }
3802 3860
3861// OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
3862// OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>();
3863// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3864// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3865//
3866// OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3867// OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3868// OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3869// OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3870
3871
3803 private void ProcessEntityUpdates(int maxUpdates) 3872 private void ProcessEntityUpdates(int maxUpdates)
3804 { 3873 {
3805 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); 3874 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
@@ -3812,6 +3881,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3812 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); 3881 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3813 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); 3882 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3814 3883
3884// objectUpdateBlocks.Value.Clear();
3885// compressedUpdateBlocks.Value.Clear();
3886// terseUpdateBlocks.Value.Clear();
3887// terseAgentUpdateBlocks.Value.Clear();
3888// objectUpdates.Value.Clear();
3889// compressedUpdates.Value.Clear();
3890// terseUpdates.Value.Clear();
3891// terseAgentUpdates.Value.Clear();
3892
3815 // Check to see if this is a flush 3893 // Check to see if this is a flush
3816 if (maxUpdates <= 0) 3894 if (maxUpdates <= 0)
3817 { 3895 {
@@ -4140,8 +4218,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4140 4218
4141 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) 4219 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
4142 { 4220 {
4221// if (!m_udpServer.IsRunningOutbound)
4222// return;
4223
4143 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) 4224 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4144 { 4225 {
4226// if (!m_udpServer.IsRunningOutbound)
4227// return;
4228
4145 if (m_maxUpdates == 0 || m_LastQueueFill == 0) 4229 if (m_maxUpdates == 0 || m_LastQueueFill == 0)
4146 { 4230 {
4147 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; 4231 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
@@ -4167,6 +4251,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4167 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); 4251 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit);
4168 } 4252 }
4169 4253
4254 internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories)
4255 {
4256 bool hasUpdates = false;
4257
4258 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4259 {
4260 if (m_entityUpdates.Count > 0)
4261 hasUpdates = true;
4262 else if (m_entityProps.Count > 0)
4263 hasUpdates = true;
4264 }
4265
4266 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
4267 {
4268 if (ImageManager.HasUpdates())
4269 hasUpdates = true;
4270 }
4271
4272 return hasUpdates;
4273 }
4274
4170 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) 4275 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
4171 { 4276 {
4172 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); 4277 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
@@ -4312,6 +4417,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4312 // Count this as a resent packet since we are going to requeue all of the updates contained in it 4417 // Count this as a resent packet since we are going to requeue all of the updates contained in it
4313 Interlocked.Increment(ref m_udpClient.PacketsResent); 4418 Interlocked.Increment(ref m_udpClient.PacketsResent);
4314 4419
4420 // We're not going to worry about interlock yet since its not currently critical that this total count
4421 // is 100% correct
4422 m_udpServer.PacketsResentCount++;
4423
4315 foreach (ObjectPropertyUpdate update in updates) 4424 foreach (ObjectPropertyUpdate update in updates)
4316 ResendPropertyUpdate(update); 4425 ResendPropertyUpdate(update);
4317 } 4426 }
@@ -4499,6 +4608,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4499 SceneObjectPart root = sop.ParentGroup.RootPart; 4608 SceneObjectPart root = sop.ParentGroup.RootPart;
4500 4609
4501 block.TouchName = Util.StringToBytes256(root.TouchName); 4610 block.TouchName = Util.StringToBytes256(root.TouchName);
4611
4612 // SL 3.3.4, at least, appears to read this information as a concatenated byte[] stream of UUIDs but
4613 // it's not yet clear whether this is actually used. If this is done in the future then a pre-cached
4614 // copy is really needed since it's less efficient to be constantly recreating this byte array.
4615// using (MemoryStream memStream = new MemoryStream())
4616// {
4617// using (BinaryWriter binWriter = new BinaryWriter(memStream))
4618// {
4619// for (int i = 0; i < sop.GetNumberOfSides(); i++)
4620// {
4621// Primitive.TextureEntryFace teFace = sop.Shape.Textures.FaceTextures[i];
4622//
4623// UUID textureID;
4624//
4625// if (teFace != null)
4626// textureID = teFace.TextureID;
4627// else
4628// textureID = sop.Shape.Textures.DefaultTexture.TextureID;
4629//
4630// binWriter.Write(textureID.GetBytes());
4631// }
4632//
4633// block.TextureID = memStream.ToArray();
4634// }
4635// }
4636
4502 block.TextureID = new byte[0]; // TextureID ??? 4637 block.TextureID = new byte[0]; // TextureID ???
4503 block.SitName = Util.StringToBytes256(root.SitName); 4638 block.SitName = Util.StringToBytes256(root.SitName);
4504 block.OwnerMask = root.OwnerMask; 4639 block.OwnerMask = root.OwnerMask;
@@ -4877,7 +5012,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4877 5012
4878 public void SendForceClientSelectObjects(List<uint> ObjectIDs) 5013 public void SendForceClientSelectObjects(List<uint> ObjectIDs)
4879 { 5014 {
4880 m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); 5015// m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count);
4881 5016
4882 bool firstCall = true; 5017 bool firstCall = true;
4883 const int MAX_OBJECTS_PER_PACKET = 251; 5018 const int MAX_OBJECTS_PER_PACKET = 251;
@@ -5015,15 +5150,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5015 } 5150 }
5016 5151
5017 attachPoint = 0; 5152 attachPoint = 0;
5153// m_log.DebugFormat(
5154// "[LLCLIENTVIEW]: Sending terse update to {0} with position {1} in {2}", Name, presence.OffsetPosition, m_scene.Name);
5155
5156 // attachPoint = presence.State; // Core: commented
5018 collisionPlane = presence.CollisionPlane; 5157 collisionPlane = presence.CollisionPlane;
5019 velocity = presence.Velocity; 5158 velocity = presence.Velocity;
5020 acceleration = Vector3.Zero; 5159 acceleration = Vector3.Zero;
5021 5160
5022 // Interestingly, sending this to non-zero will cause the client's avatar to start moving & accelerating
5023 // in that direction, even though we don't model this on the server. Implementing this in the future
5024 // may improve movement smoothness.
5025// acceleration = new Vector3(1, 0, 0);
5026
5027 if (sendTexture) 5161 if (sendTexture)
5028 textureEntry = presence.Appearance.Texture.GetBytes(); 5162 textureEntry = presence.Appearance.Texture.GetBytes();
5029 else 5163 else
@@ -5034,7 +5168,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5034 SceneObjectPart part = (SceneObjectPart)entity; 5168 SceneObjectPart part = (SceneObjectPart)entity;
5035 5169
5036 attachPoint = part.ParentGroup.AttachmentPoint; 5170 attachPoint = part.ParentGroup.AttachmentPoint;
5037 5171 attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16));
5038// m_log.DebugFormat( 5172// m_log.DebugFormat(
5039// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", 5173// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}",
5040// attachPoint, part.Name, part.LocalId, Name); 5174// attachPoint, part.Name, part.LocalId, Name);
@@ -5062,7 +5196,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5062 pos += 4; 5196 pos += 4;
5063 5197
5064 // Avatar/CollisionPlane 5198 // Avatar/CollisionPlane
5065 data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ; 5199 data[pos++] = (byte) attachPoint;
5066 if (avatar) 5200 if (avatar)
5067 { 5201 {
5068 data[pos++] = 1; 5202 data[pos++] = 1;
@@ -5143,6 +5277,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5143 parentID = part.ParentGroup.RootPart.LocalId; 5277 parentID = part.ParentGroup.RootPart.LocalId;
5144 } 5278 }
5145 } 5279 }
5280// m_log.DebugFormat(
5281// "[LLCLIENTVIEW]: Sending full update to {0} with position {1} in {2}", Name, data.OffsetPosition, m_scene.Name);
5146 5282
5147 byte[] objectData = new byte[76]; 5283 byte[] objectData = new byte[76];
5148 5284
@@ -5168,7 +5304,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5168 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + 5304 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
5169 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); 5305 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
5170 update.ObjectData = objectData; 5306 update.ObjectData = objectData;
5171 update.ParentID = parentID; 5307
5308 SceneObjectPart parentPart = data.ParentPart;
5309 if (parentPart != null)
5310 update.ParentID = parentPart.ParentGroup.LocalId;
5311 else
5312 update.ParentID = 0;
5313
5172 update.PathCurve = 16; 5314 update.PathCurve = 16;
5173 update.PathScaleX = 100; 5315 update.PathScaleX = 100;
5174 update.PathScaleY = 100; 5316 update.PathScaleY = 100;
@@ -5387,7 +5529,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5387 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); 5529 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject);
5388 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); 5530 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject);
5389 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); 5531 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand);
5390 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply); 5532 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false);
5391 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); 5533 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest);
5392 AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance); 5534 AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance);
5393 AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing); 5535 AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing);
@@ -5448,8 +5590,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5448 AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); 5590 AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false);
5449 AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); 5591 AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false);
5450 AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); 5592 AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false);
5451 AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage); 5593 AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false);
5452 AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest); 5594 AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false);
5453 AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); 5595 AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest);
5454 AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); 5596 AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer);
5455 AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); 5597 AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket);
@@ -5481,7 +5623,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5481 AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); 5623 AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel);
5482 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); 5624 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest);
5483 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); 5625 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false);
5484 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest); 5626 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest, false);
5485 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); 5627 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest);
5486 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); 5628 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false);
5487 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); 5629 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false);
@@ -5594,83 +5736,137 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5594 5736
5595 #region Packet Handlers 5737 #region Packet Handlers
5596 5738
5739 public int TotalAgentUpdates { get; set; }
5740
5597 #region Scene/Avatar 5741 #region Scene/Avatar
5598 5742
5599 private bool HandleAgentUpdate(IClientAPI sener, Packet packet) 5743 // Threshold for body rotation to be a significant agent update
5744 private const float QDELTA = 0.000001f;
5745 // Threshold for camera rotation to be a significant agent update
5746 private const float VDELTA = 0.01f;
5747
5748 /// <summary>
5749 /// This checks the update significance against the last update made.
5750 /// </summary>
5751 /// <remarks>Can only be called by one thread at a time</remarks>
5752 /// <returns></returns>
5753 /// <param name='x'></param>
5754 public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5600 { 5755 {
5601 if (OnAgentUpdate != null) 5756 return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x);
5602 { 5757 }
5603 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5604 5758
5605 #region Packet Session and User Check 5759 /// <summary>
5606 if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId) 5760 /// This checks the movement/state update significance against the last update made.
5607 { 5761 /// </summary>
5608 PacketPool.Instance.ReturnPacket(packet); 5762 /// <remarks>Can only be called by one thread at a time</remarks>
5609 return false; 5763 /// <returns></returns>
5610 } 5764 /// <param name='x'></param>
5611 #endregion 5765 private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5766 {
5767 float qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2);
5768 //qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2);
5769
5770 bool movementSignificant =
5771 (qdelta1 > QDELTA) // significant if body rotation above threshold
5772 // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack
5773 // || (qdelta2 > QDELTA * 10) // significant if head rotation above threshold
5774 || (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed
5775 || (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands
5776 || (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed
5777 || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed
5778 || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed
5779 ;
5780 //if (movementSignificant)
5781 //{
5782 //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}",
5783 // qdelta1, qdelta2);
5784 //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}",
5785 // x.ControlFlags, x.Flags, x.Far, x.State);
5786 //}
5787 return movementSignificant;
5788 }
5612 5789
5613 bool update = false; 5790 /// <summary>
5614 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; 5791 /// This checks the camera update significance against the last update made.
5615 5792 /// </summary>
5616 if (m_lastAgentUpdateArgs != null) 5793 /// <remarks>Can only be called by one thread at a time</remarks>
5617 { 5794 /// <returns></returns>
5618 // These should be ordered from most-likely to 5795 /// <param name='x'></param>
5619 // least likely to change. I've made an initial 5796 private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5620 // guess at that. 5797 {
5621 update = 5798 float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis);
5622 ( 5799 float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter);
5623 (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || 5800 float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis);
5624 (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || 5801 float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis);
5625 (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) ||
5626 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
5627 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
5628 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
5629 (x.ControlFlags != 0) ||
5630 (x.Far != m_lastAgentUpdateArgs.Far) ||
5631 (x.Flags != m_lastAgentUpdateArgs.Flags) ||
5632 (x.State != m_lastAgentUpdateArgs.State) ||
5633 (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) ||
5634 (x.SessionID != m_lastAgentUpdateArgs.SessionID) ||
5635 (x.AgentID != m_lastAgentUpdateArgs.AgentID)
5636 );
5637 }
5638 else
5639 {
5640 m_lastAgentUpdateArgs = new AgentUpdateArgs();
5641 update = true;
5642 }
5643 5802
5644 if (update) 5803 bool cameraSignificant =
5645 { 5804 (vdelta1 > VDELTA) ||
5646// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); 5805 (vdelta2 > VDELTA) ||
5806 (vdelta3 > VDELTA) ||
5807 (vdelta4 > VDELTA)
5808 ;
5647 5809
5648 m_lastAgentUpdateArgs.AgentID = x.AgentID; 5810 //if (cameraSignificant)
5649 m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; 5811 //{
5650 m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; 5812 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}",
5651 m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter; 5813 // x.CameraAtAxis, x.CameraCenter);
5652 m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; 5814 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}",
5653 m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; 5815 // x.CameraLeftAxis, x.CameraUpAxis);
5654 m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags; 5816 //}
5655 m_lastAgentUpdateArgs.Far = x.Far;
5656 m_lastAgentUpdateArgs.Flags = x.Flags;
5657 m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation;
5658 m_lastAgentUpdateArgs.SessionID = x.SessionID;
5659 m_lastAgentUpdateArgs.State = x.State;
5660 5817
5661 UpdateAgent handlerAgentUpdate = OnAgentUpdate; 5818 return cameraSignificant;
5662 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; 5819 }
5663 5820
5664 if (handlerPreAgentUpdate != null) 5821 private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
5665 OnPreAgentUpdate(this, m_lastAgentUpdateArgs); 5822 {
5823 // We got here, which means that something in agent update was significant
5666 5824
5667 if (handlerAgentUpdate != null) 5825 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5668 OnAgentUpdate(this, m_lastAgentUpdateArgs); 5826 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
5669 5827
5670 handlerAgentUpdate = null; 5828 if (x.AgentID != AgentId || x.SessionID != SessionId)
5671 handlerPreAgentUpdate = null; 5829 return false;
5672 } 5830
5673 } 5831 // Before we update the current m_thisAgentUpdateArgs, let's check this again
5832 // to see what exactly changed
5833 bool movement = CheckAgentMovementUpdateSignificance(x);
5834 bool camera = CheckAgentCameraUpdateSignificance(x);
5835
5836 m_thisAgentUpdateArgs.AgentID = x.AgentID;
5837 m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation;
5838 m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
5839 m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter;
5840 m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
5841 m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
5842 m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags;
5843 m_thisAgentUpdateArgs.Far = x.Far;
5844 m_thisAgentUpdateArgs.Flags = x.Flags;
5845 m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation;
5846 m_thisAgentUpdateArgs.SessionID = x.SessionID;
5847 m_thisAgentUpdateArgs.State = x.State;
5848
5849 UpdateAgent handlerAgentUpdate = OnAgentUpdate;
5850 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
5851 UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate;
5852
5853 // Was there a significant movement/state change?
5854 if (movement)
5855 {
5856 if (handlerPreAgentUpdate != null)
5857 OnPreAgentUpdate(this, m_thisAgentUpdateArgs);
5858
5859 if (handlerAgentUpdate != null)
5860 OnAgentUpdate(this, m_thisAgentUpdateArgs);
5861 }
5862 // Was there a significant camera(s) change?
5863 if (camera)
5864 if (handlerAgentCameraUpdate != null)
5865 handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs);
5866
5867 handlerAgentUpdate = null;
5868 handlerPreAgentUpdate = null;
5869 handlerAgentCameraUpdate = null;
5674 5870
5675 PacketPool.Instance.ReturnPacket(packet); 5871 PacketPool.Instance.ReturnPacket(packet);
5676 5872
@@ -6260,6 +6456,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6260 //m_log.Info("[LAND]: LAND:" + modify.ToString()); 6456 //m_log.Info("[LAND]: LAND:" + modify.ToString());
6261 if (modify.ParcelData.Length > 0) 6457 if (modify.ParcelData.Length > 0)
6262 { 6458 {
6459 // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore,
6460 // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit.
6461 m_justEditedTerrain = true; // Prevent terrain packet (Land layer) from being queued, make it unreliable
6263 if (OnModifyTerrain != null) 6462 if (OnModifyTerrain != null)
6264 { 6463 {
6265 for (int i = 0; i < modify.ParcelData.Length; i++) 6464 for (int i = 0; i < modify.ParcelData.Length; i++)
@@ -6275,6 +6474,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6275 } 6474 }
6276 } 6475 }
6277 } 6476 }
6477 m_justEditedTerrain = false; // Queue terrain packet (Land layer) if necessary, make it reliable again
6278 } 6478 }
6279 6479
6280 return true; 6480 return true;
@@ -6636,6 +6836,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6636 } 6836 }
6637 #endregion 6837 #endregion
6638 6838
6839 if (SceneAgent.IsChildAgent)
6840 {
6841 SendCantSitBecauseChildAgentResponse();
6842 return true;
6843 }
6844
6639 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; 6845 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit;
6640 6846
6641 if (handlerAgentRequestSit != null) 6847 if (handlerAgentRequestSit != null)
@@ -6660,6 +6866,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6660 } 6866 }
6661 #endregion 6867 #endregion
6662 6868
6869 if (SceneAgent.IsChildAgent)
6870 {
6871 SendCantSitBecauseChildAgentResponse();
6872 return true;
6873 }
6874
6663 AgentSit handlerAgentSit = OnAgentSit; 6875 AgentSit handlerAgentSit = OnAgentSit;
6664 if (handlerAgentSit != null) 6876 if (handlerAgentSit != null)
6665 { 6877 {
@@ -6669,6 +6881,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6669 return true; 6881 return true;
6670 } 6882 }
6671 6883
6884 /// <summary>
6885 /// Used when a child agent gets a sit response which should not be fulfilled.
6886 /// </summary>
6887 private void SendCantSitBecauseChildAgentResponse()
6888 {
6889 SendAlertMessage("Try moving closer. Can't sit on object because it is not in the same region as you.");
6890 }
6891
6672 private bool HandleSoundTrigger(IClientAPI sender, Packet Pack) 6892 private bool HandleSoundTrigger(IClientAPI sender, Packet Pack)
6673 { 6893 {
6674 SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack; 6894 SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack;
@@ -7879,129 +8099,145 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7879 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); 8099 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request");
7880 8100
7881 TransferRequestPacket transfer = (TransferRequestPacket)Pack; 8101 TransferRequestPacket transfer = (TransferRequestPacket)Pack;
7882 //m_log.Debug("Transfer Request: " + transfer.ToString());
7883 // Validate inventory transfers
7884 // Has to be done here, because AssetCache can't do it
7885 //
7886 UUID taskID = UUID.Zero; 8102 UUID taskID = UUID.Zero;
7887 if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) 8103 if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem)
7888 { 8104 {
7889 taskID = new UUID(transfer.TransferInfo.Params, 48);
7890 UUID itemID = new UUID(transfer.TransferInfo.Params, 64);
7891 UUID requestID = new UUID(transfer.TransferInfo.Params, 80);
7892
7893// m_log.DebugFormat(
7894// "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}",
7895// requestID, itemID, taskID, Name);
7896
7897 if (!(((Scene)m_scene).Permissions.BypassPermissions())) 8105 if (!(((Scene)m_scene).Permissions.BypassPermissions()))
7898 { 8106 {
7899 if (taskID != UUID.Zero) // Prim 8107 // We're spawning a thread because the permissions check can block this thread
8108 Util.FireAndForget(delegate
7900 { 8109 {
7901 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); 8110 // This requests the asset if needed
8111 HandleSimInventoryTransferRequestWithPermsCheck(sender, transfer);
8112 });
8113 return true;
8114 }
8115 }
8116 else if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate)
8117 {
8118 //TransferRequestPacket does not include covenant uuid?
8119 //get scene covenant uuid
8120 taskID = m_scene.RegionInfo.RegionSettings.Covenant;
8121 }
7902 8122
7903 if (part == null) 8123 // This is non-blocking
7904 { 8124 MakeAssetRequest(transfer, taskID);
7905 m_log.WarnFormat(
7906 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist",
7907 Name, requestID, itemID, taskID);
7908 return true;
7909 }
7910 8125
7911 TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); 8126 return true;
7912 if (tii == null) 8127 }
7913 {
7914 m_log.WarnFormat(
7915 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist",
7916 Name, requestID, itemID, taskID);
7917 return true;
7918 }
7919 8128
7920 if (tii.Type == (int)AssetType.LSLText) 8129 private void HandleSimInventoryTransferRequestWithPermsCheck(IClientAPI sender, TransferRequestPacket transfer)
7921 { 8130 {
7922 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) 8131 UUID taskID = new UUID(transfer.TransferInfo.Params, 48);
7923 return true; 8132 UUID itemID = new UUID(transfer.TransferInfo.Params, 64);
7924 } 8133 UUID requestID = new UUID(transfer.TransferInfo.Params, 80);
7925 else if (tii.Type == (int)AssetType.Notecard)
7926 {
7927 if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId))
7928 return true;
7929 }
7930 else
7931 {
7932 // TODO: Change this code to allow items other than notecards and scripts to be successfully
7933 // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule
7934 if (part.OwnerID != AgentId)
7935 {
7936 m_log.WarnFormat(
7937 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}",
7938 Name, requestID, itemID, taskID, part.OwnerID);
7939 return true;
7940 }
7941 8134
7942 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) 8135 //m_log.DebugFormat(
7943 { 8136 // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}",
7944 m_log.WarnFormat( 8137 // requestID, itemID, taskID, Name);
7945 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set",
7946 Name, requestID, itemID, taskID);
7947 return true;
7948 }
7949 8138
7950 if (tii.OwnerID != AgentId) 8139 //m_log.Debug("Transfer Request: " + transfer.ToString());
7951 { 8140 // Validate inventory transfers
7952 m_log.WarnFormat( 8141 // Has to be done here, because AssetCache can't do it
7953 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}", 8142 //
7954 Name, requestID, itemID, taskID, tii.OwnerID); 8143 if (taskID != UUID.Zero) // Prim
7955 return true; 8144 {
7956 } 8145 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID);
7957 8146
7958 if (( 8147 if (part == null)
7959 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) 8148 {
7960 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) 8149 m_log.WarnFormat(
7961 { 8150 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist",
7962 m_log.WarnFormat( 8151 Name, requestID, itemID, taskID);
7963 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", 8152 return;
7964 Name, requestID, itemID, taskID); 8153 }
7965 return true;
7966 }
7967 8154
7968 if (tii.AssetID != requestID) 8155 TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID);
7969 { 8156 if (tii == null)
7970 m_log.WarnFormat( 8157 {
7971 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", 8158 m_log.WarnFormat(
7972 Name, requestID, itemID, taskID, tii.AssetID); 8159 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist",
7973 return true; 8160 Name, requestID, itemID, taskID);
7974 } 8161 return;
7975 } 8162 }
8163
8164 if (tii.Type == (int)AssetType.LSLText)
8165 {
8166 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId))
8167 return;
8168 }
8169 else if (tii.Type == (int)AssetType.Notecard)
8170 {
8171 if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId))
8172 return;
8173 }
8174 else
8175 {
8176 // TODO: Change this code to allow items other than notecards and scripts to be successfully
8177 // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule
8178 if (part.OwnerID != AgentId)
8179 {
8180 m_log.WarnFormat(
8181 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}",
8182 Name, requestID, itemID, taskID, part.OwnerID);
8183 return;
7976 } 8184 }
7977 else // Agent 8185
8186 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0)
7978 { 8187 {
7979 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); 8188 m_log.WarnFormat(
7980 if (invAccess != null) 8189 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set",
7981 { 8190 Name, requestID, itemID, taskID);
7982 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID)) 8191 return;
7983 return false; 8192 }
7984 } 8193
7985 else 8194 if (tii.OwnerID != AgentId)
7986 { 8195 {
7987 return false; 8196 m_log.WarnFormat(
7988 } 8197 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}",
8198 Name, requestID, itemID, taskID, tii.OwnerID);
8199 return;
8200 }
8201
8202 if ((
8203 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8204 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8205 {
8206 m_log.WarnFormat(
8207 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer",
8208 Name, requestID, itemID, taskID);
8209 return;
8210 }
8211
8212 if (tii.AssetID != requestID)
8213 {
8214 m_log.WarnFormat(
8215 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}",
8216 Name, requestID, itemID, taskID, tii.AssetID);
8217 return;
7989 } 8218 }
7990 } 8219 }
7991 } 8220 }
7992 else 8221 else // Agent
7993 if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate) 8222 {
8223 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
8224 if (invAccess != null)
7994 { 8225 {
7995 //TransferRequestPacket does not include covenant uuid? 8226 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID))
7996 //get scene covenant uuid 8227 return;
7997 taskID = m_scene.RegionInfo.RegionSettings.Covenant;
7998 } 8228 }
8229 else
8230 {
8231 return;
8232 }
8233 }
7999 8234
8235 // Permissions out of the way, let's request the asset
8000 MakeAssetRequest(transfer, taskID); 8236 MakeAssetRequest(transfer, taskID);
8001 8237
8002 return true;
8003 } 8238 }
8004 8239
8240
8005 private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack) 8241 private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack)
8006 { 8242 {
8007 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; 8243 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack;
@@ -11732,8 +11968,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11732 } 11968 }
11733 11969
11734 /// <summary> 11970 /// <summary>
11735 /// Send a response back to a client when it asks the asset server (via the region server) if it has
11736 /// its appearance texture cached.
11737 /// </summary> 11971 /// </summary>
11738 /// <remarks> 11972 /// <remarks>
11739 /// At the moment, we always reply that there is no cached texture. 11973 /// At the moment, we always reply that there is no cached texture.
@@ -11741,6 +11975,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11741 /// <param name="simclient"></param> 11975 /// <param name="simclient"></param>
11742 /// <param name="packet"></param> 11976 /// <param name="packet"></param>
11743 /// <returns></returns> 11977 /// <returns></returns>
11978 // TODO: Convert old handler to use new method
11979 /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11980 {
11981 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11982
11983 if (cachedtex.AgentData.SessionID != SessionId)
11984 return false;
11985
11986
11987 List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>();
11988
11989 for (int i = 0; i < cachedtex.WearableData.Length; i++)
11990 {
11991 CachedTextureRequestArg arg = new CachedTextureRequestArg();
11992 arg.BakedTextureIndex = cachedtex.WearableData[i].TextureIndex;
11993 arg.WearableHashID = cachedtex.WearableData[i].ID;
11994
11995 requestArgs.Add(arg);
11996 }
11997
11998 CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest;
11999 if (handlerCachedTextureRequest != null)
12000 {
12001 handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs);
12002 }
12003
12004 return true;
12005 }*/
12006
11744 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) 12007 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11745 { 12008 {
11746 //m_log.Debug("texture cached: " + packet.ToString()); 12009 //m_log.Debug("texture cached: " + packet.ToString());
@@ -11899,6 +12162,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11899 return true; 12162 return true;
11900 } 12163 }
11901 12164
12165 /// <summary>
12166 /// Send a response back to a client when it asks the asset server (via the region server) if it has
12167 /// its appearance texture cached.
12168 /// </summary>
12169 /// <param name="avatar"></param>
12170 /// <param name="serial"></param>
12171 /// <param name="cachedTextures"></param>
12172 /// <returns></returns>
12173 public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures)
12174 {
12175 ScenePresence presence = avatar as ScenePresence;
12176 if (presence == null)
12177 return;
12178
12179 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
12180
12181 // TODO: don't create new blocks if recycling an old packet
12182 cachedresp.AgentData.AgentID = m_agentId;
12183 cachedresp.AgentData.SessionID = m_sessionId;
12184 cachedresp.AgentData.SerialNum = serial;
12185 cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cachedTextures.Count];
12186
12187 for (int i = 0; i < cachedTextures.Count; i++)
12188 {
12189 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12190 cachedresp.WearableData[i].TextureIndex = (byte)cachedTextures[i].BakedTextureIndex;
12191 cachedresp.WearableData[i].TextureID = cachedTextures[i].BakedTextureID;
12192 cachedresp.WearableData[i].HostName = new byte[0];
12193 }
12194
12195 cachedresp.Header.Zerocoded = true;
12196 OutPacket(cachedresp, ThrottleOutPacketType.Task);
12197 }
12198
11902 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) 12199 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet)
11903 { 12200 {
11904 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; 12201 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet;
@@ -11924,8 +12221,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11924 if (part == null) 12221 if (part == null)
11925 { 12222 {
11926 // It's a ghost! tell the client to delete it from view. 12223 // It's a ghost! tell the client to delete it from view.
11927 simClient.SendKillObject(Scene.RegionInfo.RegionHandle, 12224 simClient.SendKillObject(new List<uint> { localId });
11928 new List<uint> { localId });
11929 } 12225 }
11930 else 12226 else
11931 { 12227 {
@@ -12299,6 +12595,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12299 12595
12300 shape.PCode = addPacket.ObjectData.PCode; 12596 shape.PCode = addPacket.ObjectData.PCode;
12301 shape.State = addPacket.ObjectData.State; 12597 shape.State = addPacket.ObjectData.State;
12598 shape.LastAttachPoint = addPacket.ObjectData.State;
12302 shape.PathBegin = addPacket.ObjectData.PathBegin; 12599 shape.PathBegin = addPacket.ObjectData.PathBegin;
12303 shape.PathEnd = addPacket.ObjectData.PathEnd; 12600 shape.PathEnd = addPacket.ObjectData.PathEnd;
12304 shape.PathScaleX = addPacket.ObjectData.PathScaleX; 12601 shape.PathScaleX = addPacket.ObjectData.PathScaleX;
@@ -12329,7 +12626,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12329 ClientInfo info = m_udpClient.GetClientInfo(); 12626 ClientInfo info = m_udpClient.GetClientInfo();
12330 12627
12331 info.proxyEP = null; 12628 info.proxyEP = null;
12332 info.agentcircuit = RequestClientInfo(); 12629 if (info.agentcircuit == null)
12630 info.agentcircuit = RequestClientInfo();
12333 12631
12334 return info; 12632 return info;
12335 } 12633 }
@@ -12712,11 +13010,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12712 OutPacket(dialog, ThrottleOutPacketType.Task); 13010 OutPacket(dialog, ThrottleOutPacketType.Task);
12713 } 13011 }
12714 13012
12715 public void StopFlying(ISceneEntity p) 13013 public void SendAgentTerseUpdate(ISceneEntity p)
12716 { 13014 {
12717 if (p is ScenePresence) 13015 if (p is ScenePresence)
12718 { 13016 {
12719 ScenePresence presence = p as ScenePresence; 13017// m_log.DebugFormat(
13018// "[LLCLIENTVIEW]: Immediately sending terse agent update for {0} to {1} in {2}",
13019// p.Name, Name, Scene.Name);
13020
12720 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities 13021 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities
12721 // There's no explicit message to send the client to tell it to stop flying.. it relies on the 13022 // There's no explicit message to send the client to tell it to stop flying.. it relies on the
12722 // velocity, collision plane and avatar height 13023 // velocity, collision plane and avatar height
@@ -12724,34 +13025,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12724 // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air 13025 // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air
12725 // when the avatar stands up 13026 // when the avatar stands up
12726 13027
12727 Vector3 pos = presence.AbsolutePosition;
12728
12729 if (presence.Appearance.AvatarHeight != 127.0f)
12730 pos += new Vector3(0f, 0f, (presence.Appearance.AvatarHeight/6f));
12731 else
12732 pos += new Vector3(0f, 0f, (1.56f/6f));
12733
12734 presence.AbsolutePosition = pos;
12735
12736 // attach a suitable collision plane regardless of the actual situation to force the LLClient to land.
12737 // Collision plane below the avatar's position a 6th of the avatar's height is suitable.
12738 // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a
12739 // certain amount.. because the LLClient wouldn't land in that situation anyway.
12740
12741 // why are we still testing for this really old height value default???
12742 if (presence.Appearance.AvatarHeight != 127.0f)
12743 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - presence.Appearance.AvatarHeight/6f);
12744 else
12745 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f/6f));
12746
12747
12748 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = 13028 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block =
12749 CreateImprovedTerseBlock(p, false); 13029 CreateImprovedTerseBlock(p, false);
12750 13030
12751 const float TIME_DILATION = 1.0f; 13031 const float TIME_DILATION = 1.0f;
12752 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); 13032 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
12753 13033
12754
12755 ImprovedTerseObjectUpdatePacket packet 13034 ImprovedTerseObjectUpdatePacket packet
12756 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( 13035 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
12757 PacketType.ImprovedTerseObjectUpdate); 13036 PacketType.ImprovedTerseObjectUpdate);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
index 073c357..41dd4d1 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
@@ -206,6 +206,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
206 } 206 }
207 } 207 }
208 208
209 public bool HasUpdates()
210 {
211 J2KImage image = GetHighestPriorityImage();
212
213 return image != null && image.IsDecoded;
214 }
215
209 public bool ProcessImageQueue(int packetsToSend) 216 public bool ProcessImageQueue(int packetsToSend)
210 { 217 {
211 int packetsSent = 0; 218 int packetsSent = 0;
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index e52ac37..bd4e617 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -31,6 +31,7 @@ using System.Net;
31using System.Threading; 31using System.Threading;
32using log4net; 32using log4net;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Monitoring;
34using OpenMetaverse; 35using OpenMetaverse;
35using OpenMetaverse.Packets; 36using OpenMetaverse.Packets;
36 37
@@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
81 /// hooked to put more data on the empty queue</summary> 82 /// hooked to put more data on the empty queue</summary>
82 public event QueueEmpty OnQueueEmpty; 83 public event QueueEmpty OnQueueEmpty;
83 84
85 public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates;
86
84 /// <summary>AgentID for this client</summary> 87 /// <summary>AgentID for this client</summary>
85 public readonly UUID AgentID; 88 public readonly UUID AgentID;
86 /// <summary>The remote address of the connected client</summary> 89 /// <summary>The remote address of the connected client</summary>
@@ -161,6 +164,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
161 public bool m_deliverPackets = true; 164 public bool m_deliverPackets = true;
162 165
163 /// <summary> 166 /// <summary>
167 /// This is the percentage of the udp texture queue to add to the task queue since
168 /// textures are now generally handled through http.
169 /// </summary>
170 private double m_cannibalrate = 0.0;
171
172 private ClientInfo m_info = new ClientInfo();
173
174 /// <summary>
164 /// Default constructor 175 /// Default constructor
165 /// </summary> 176 /// </summary>
166 /// <param name="server">Reference to the UDP server this client is connected to</param> 177 /// <param name="server">Reference to the UDP server this client is connected to</param>
@@ -197,6 +208,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
197 // Create an array of token buckets for this clients different throttle categories 208 // Create an array of token buckets for this clients different throttle categories
198 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; 209 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
199 210
211 m_cannibalrate = rates.CannibalizeTextureRate;
212
200 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) 213 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
201 { 214 {
202 ThrottleOutPacketType type = (ThrottleOutPacketType)i; 215 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
@@ -241,20 +254,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
241 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists 254 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists
242 // of pending and needed ACKs for every client every time some method wants information about 255 // of pending and needed ACKs for every client every time some method wants information about
243 // this connection is a recipe for poor performance 256 // this connection is a recipe for poor performance
244 ClientInfo info = new ClientInfo(); 257
245 info.pendingAcks = new Dictionary<uint, uint>(); 258 m_info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
246 info.needAck = new Dictionary<uint, byte[]>(); 259 m_info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
247 260 m_info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
248 info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; 261 m_info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
249 info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; 262 m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
250 info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; 263 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
251 info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; 264 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
252 info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; 265 m_info.totalThrottle = (int)m_throttleCategory.DripRate;
253 info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; 266
254 info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; 267 return m_info;
255 info.totalThrottle = (int)m_throttleCategory.DripRate;
256
257 return info;
258 } 268 }
259 269
260 /// <summary> 270 /// <summary>
@@ -348,6 +358,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
348 texture = Math.Max(texture, LLUDPServer.MTU); 358 texture = Math.Max(texture, LLUDPServer.MTU);
349 asset = Math.Max(asset, LLUDPServer.MTU); 359 asset = Math.Max(asset, LLUDPServer.MTU);
350 360
361 // Since most textures are now delivered through http, make it possible
362 // to cannibalize some of the bw from the texture throttle to use for
363 // the task queue (e.g. object updates)
364 task = task + (int)(m_cannibalrate * texture);
365 texture = (int)((1 - m_cannibalrate) * texture);
366
351 //int total = resend + land + wind + cloud + task + texture + asset; 367 //int total = resend + land + wind + cloud + task + texture + asset;
352 //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}", 368 //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}",
353 // AgentID, resend, land, wind, cloud, task, texture, asset, total); 369 // AgentID, resend, land, wind, cloud, task, texture, asset, total);
@@ -646,15 +662,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
646 /// <param name="categories">Throttle categories to fire the callback for</param> 662 /// <param name="categories">Throttle categories to fire the callback for</param>
647 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) 663 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
648 { 664 {
649 if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) 665// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
666 if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
650 { 667 {
668 m_isQueueEmptyRunning = true;
669
670 int start = Environment.TickCount & Int32.MaxValue;
671 const int MIN_CALLBACK_MS = 30;
672
673 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
674 if (m_nextOnQueueEmpty == 0)
675 m_nextOnQueueEmpty = 1;
676
651 // Use a value of 0 to signal that FireQueueEmpty is running 677 // Use a value of 0 to signal that FireQueueEmpty is running
652 m_nextOnQueueEmpty = 0; 678// m_nextOnQueueEmpty = 0;
653 // Asynchronously run the callback 679
654 Util.FireAndForget(FireQueueEmpty, categories); 680 m_categories = categories;
681
682 if (HasUpdates(m_categories))
683 {
684 // Asynchronously run the callback
685 Util.FireAndForget(FireQueueEmpty, categories);
686 }
687 else
688 {
689 m_isQueueEmptyRunning = false;
690 }
655 } 691 }
656 } 692 }
657 693
694 private bool m_isQueueEmptyRunning;
695 private ThrottleOutPacketTypeFlags m_categories = 0;
696
658 /// <summary> 697 /// <summary>
659 /// Fires the OnQueueEmpty callback and sets the minimum time that it 698 /// Fires the OnQueueEmpty callback and sets the minimum time that it
660 /// can be called again 699 /// can be called again
@@ -664,22 +703,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
664 /// signature</param> 703 /// signature</param>
665 private void FireQueueEmpty(object o) 704 private void FireQueueEmpty(object o)
666 { 705 {
667 const int MIN_CALLBACK_MS = 30; 706// int start = Environment.TickCount & Int32.MaxValue;
707// const int MIN_CALLBACK_MS = 30;
668 708
669 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; 709// if (m_udpServer.IsRunningOutbound)
670 QueueEmpty callback = OnQueueEmpty; 710// {
671 711 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
672 int start = Environment.TickCount & Int32.MaxValue; 712 QueueEmpty callback = OnQueueEmpty;
673 713
674 if (callback != null) 714 if (callback != null)
675 { 715 {
676 try { callback(categories); } 716// if (m_udpServer.IsRunningOutbound)
677 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } 717// {
678 } 718 try { callback(categories); }
719 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
720// }
721 }
722// }
723
724// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
725// if (m_nextOnQueueEmpty == 0)
726// m_nextOnQueueEmpty = 1;
727
728// }
679 729
680 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; 730 m_isQueueEmptyRunning = false;
681 if (m_nextOnQueueEmpty == 0)
682 m_nextOnQueueEmpty = 1;
683 } 731 }
684 internal void ForceThrottleSetting(int throttle, int setting) 732 internal void ForceThrottleSetting(int throttle, int setting)
685 { 733 {
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 4154ef2..50dae2a 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -34,6 +34,7 @@ using System.Net.Sockets;
34using System.Reflection; 34using System.Reflection;
35using System.Threading; 35using System.Threading;
36using log4net; 36using log4net;
37using NDesk.Options;
37using Nini.Config; 38using Nini.Config;
38using OpenMetaverse.Packets; 39using OpenMetaverse.Packets;
39using OpenSim.Framework; 40using OpenSim.Framework;
@@ -62,20 +63,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP
62 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); 63 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager);
63 } 64 }
64 65
65 public void NetworkStop()
66 {
67 m_udpServer.Stop();
68 }
69
70 public void AddScene(IScene scene) 66 public void AddScene(IScene scene)
71 { 67 {
72 m_udpServer.AddScene(scene); 68 m_udpServer.AddScene(scene);
73 69
74 StatsManager.RegisterStat( 70 StatsManager.RegisterStat(
75 new Stat( 71 new Stat(
72 "ClientLogoutsDueToNoReceives",
73 "Number of times a client has been logged out because no packets were received before the timeout.",
74 "",
75 "",
76 "clientstack",
77 scene.Name,
78 StatType.Pull,
79 MeasuresOfInterest.None,
80 stat => stat.Value = m_udpServer.ClientLogoutsDueToNoReceives,
81 StatVerbosity.Debug));
82
83 StatsManager.RegisterStat(
84 new Stat(
85 "IncomingUDPReceivesCount",
86 "Number of UDP receives performed",
87 "",
88 "",
89 "clientstack",
90 scene.Name,
91 StatType.Pull,
92 MeasuresOfInterest.AverageChangeOverTime,
93 stat => stat.Value = m_udpServer.UdpReceives,
94 StatVerbosity.Debug));
95
96 StatsManager.RegisterStat(
97 new Stat(
76 "IncomingPacketsProcessedCount", 98 "IncomingPacketsProcessedCount",
77 "Number of inbound UDP packets processed", 99 "Number of inbound LL protocol packets processed",
78 "Number of inbound UDP packets processed", 100 "",
79 "", 101 "",
80 "clientstack", 102 "clientstack",
81 scene.Name, 103 scene.Name,
@@ -83,6 +105,86 @@ namespace OpenSim.Region.ClientStack.LindenUDP
83 MeasuresOfInterest.AverageChangeOverTime, 105 MeasuresOfInterest.AverageChangeOverTime,
84 stat => stat.Value = m_udpServer.IncomingPacketsProcessed, 106 stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
85 StatVerbosity.Debug)); 107 StatVerbosity.Debug));
108
109 StatsManager.RegisterStat(
110 new Stat(
111 "IncomingPacketsMalformedCount",
112 "Number of inbound UDP packets that could not be recognized as LL protocol packets.",
113 "",
114 "",
115 "clientstack",
116 scene.Name,
117 StatType.Pull,
118 MeasuresOfInterest.AverageChangeOverTime,
119 stat => stat.Value = m_udpServer.IncomingMalformedPacketCount,
120 StatVerbosity.Info));
121
122 StatsManager.RegisterStat(
123 new Stat(
124 "IncomingPacketsOrphanedCount",
125 "Number of inbound packets that were not initial connections packets and could not be associated with a viewer.",
126 "",
127 "",
128 "clientstack",
129 scene.Name,
130 StatType.Pull,
131 MeasuresOfInterest.AverageChangeOverTime,
132 stat => stat.Value = m_udpServer.IncomingOrphanedPacketCount,
133 StatVerbosity.Info));
134
135 StatsManager.RegisterStat(
136 new Stat(
137 "IncomingPacketsResentCount",
138 "Number of inbound packets that clients indicate are resends.",
139 "",
140 "",
141 "clientstack",
142 scene.Name,
143 StatType.Pull,
144 MeasuresOfInterest.AverageChangeOverTime,
145 stat => stat.Value = m_udpServer.IncomingPacketsResentCount,
146 StatVerbosity.Debug));
147
148 StatsManager.RegisterStat(
149 new Stat(
150 "OutgoingUDPSendsCount",
151 "Number of UDP sends performed",
152 "",
153 "",
154 "clientstack",
155 scene.Name,
156 StatType.Pull,
157 MeasuresOfInterest.AverageChangeOverTime,
158 stat => stat.Value = m_udpServer.UdpSends,
159 StatVerbosity.Debug));
160
161 StatsManager.RegisterStat(
162 new Stat(
163 "OutgoingPacketsResentCount",
164 "Number of packets resent because a client did not acknowledge receipt",
165 "",
166 "",
167 "clientstack",
168 scene.Name,
169 StatType.Pull,
170 MeasuresOfInterest.AverageChangeOverTime,
171 stat => stat.Value = m_udpServer.PacketsResentCount,
172 StatVerbosity.Debug));
173
174 StatsManager.RegisterStat(
175 new Stat(
176 "AverageUDPProcessTime",
177 "Average number of milliseconds taken to process each incoming UDP packet in a sample.",
178 "This is for initial receive processing which is separate from the later client LL packet processing stage.",
179 "ms",
180 "clientstack",
181 scene.Name,
182 StatType.Pull,
183 MeasuresOfInterest.None,
184 stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond,
185// stat =>
186// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, 7),
187 StatVerbosity.Debug));
86 } 188 }
87 189
88 public bool HandlesRegion(Location x) 190 public bool HandlesRegion(Location x)
@@ -107,10 +209,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
107 /// </summary> 209 /// </summary>
108 public class LLUDPServer : OpenSimUDPBase 210 public class LLUDPServer : OpenSimUDPBase
109 { 211 {
212 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
213
110 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> 214 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary>
111 public const int MTU = 1400; 215 public const int MTU = 1400;
112 216
113 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 217 /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary>
218 public int ClientLogoutsDueToNoReceives { get; private set; }
219
220 /// <summary>
221 /// Default packet debug level given to new clients
222 /// </summary>
223 public int DefaultClientPacketDebugLevel { get; set; }
114 224
115 /// <summary>The measured resolution of Environment.TickCount</summary> 225 /// <summary>The measured resolution of Environment.TickCount</summary>
116 public readonly float TickCountResolution; 226 public readonly float TickCountResolution;
@@ -184,6 +294,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
184 protected bool m_sendPing; 294 protected bool m_sendPing;
185 295
186 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); 296 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
297
298 /// <summary>
299 /// Event used to signal when queued packets are available for sending.
300 /// </summary>
301 /// <remarks>
302 /// This allows the outbound loop to only operate when there is data to send rather than continuously polling.
303 /// Some data is sent immediately and not queued. That data would not trigger this event.
304 /// </remarks>
305 private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
306
187 private Pool<IncomingPacket> m_incomingPacketPool; 307 private Pool<IncomingPacket> m_incomingPacketPool;
188 308
189 /// <summary> 309 /// <summary>
@@ -204,7 +324,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
204 324
205 public Socket Server { get { return null; } } 325 public Socket Server { get { return null; } }
206 326
207 private int m_malformedCount = 0; // Guard against a spamming attack 327 /// <summary>
328 /// Record how many packets have been resent
329 /// </summary>
330 internal int PacketsResentCount { get; set; }
331
332 /// <summary>
333 /// Record how many packets have been sent
334 /// </summary>
335 internal int PacketsSentCount { get; set; }
336
337 /// <summary>
338 /// Record how many incoming packets are indicated as resends by clients.
339 /// </summary>
340 internal int IncomingPacketsResentCount { get; set; }
341
342 /// <summary>
343 /// Record how many inbound packets could not be recognized as LLUDP packets.
344 /// </summary>
345 public int IncomingMalformedPacketCount { get; private set; }
346
347 /// <summary>
348 /// Record how many inbound packets could not be associated with a simulator circuit.
349 /// </summary>
350 public int IncomingOrphanedPacketCount { get; private set; }
208 351
209 /// <summary> 352 /// <summary>
210 /// Record current outgoing client for monitoring purposes. 353 /// Record current outgoing client for monitoring purposes.
@@ -461,6 +604,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
461 m_scene = (Scene)scene; 604 m_scene = (Scene)scene;
462 m_location = new Location(m_scene.RegionInfo.RegionHandle); 605 m_location = new Location(m_scene.RegionInfo.RegionHandle);
463 606
607 StatsManager.RegisterStat(
608 new Stat(
609 "InboxPacketsCount",
610 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
611 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
612 "",
613 "clientstack",
614 scene.Name,
615 StatType.Pull,
616 MeasuresOfInterest.AverageChangeOverTime,
617 stat => stat.Value = packetInbox.Count,
618 StatVerbosity.Debug));
619
464 // XXX: These stats are also pool stats but we register them separately since they are currently not 620 // XXX: These stats are also pool stats but we register them separately since they are currently not
465 // turned on and off by EnablePools()/DisablePools() 621 // turned on and off by EnablePools()/DisablePools()
466 StatsManager.RegisterStat( 622 StatsManager.RegisterStat(
@@ -521,6 +677,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
521 EnablePoolStats(); 677 EnablePoolStats();
522 678
523 MainConsole.Instance.Commands.AddCommand( 679 MainConsole.Instance.Commands.AddCommand(
680 "Debug", false, "debug lludp packet",
681 "debug lludp packet [--default] <level> [<avatar-first-name> <avatar-last-name>]",
682 "Turn on packet debugging",
683 "If level > 255 then all incoming and outgoing packets are logged.\n"
684 + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n"
685 + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n"
686 + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n"
687 + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n"
688 + "If level <= 0 then no packets are logged.\n"
689 + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n"
690 + "In this case, you cannot also specify an avatar name.\n"
691 + "If an avatar name is given then only packets from that avatar are logged.",
692 HandlePacketCommand);
693
694 MainConsole.Instance.Commands.AddCommand(
524 "Debug", 695 "Debug",
525 false, 696 false,
526 "debug lludp start", 697 "debug lludp start",
@@ -559,10 +730,78 @@ namespace OpenSim.Region.ClientStack.LindenUDP
559 "debug lludp status", 730 "debug lludp status",
560 "Return status of LLUDP packet processing.", 731 "Return status of LLUDP packet processing.",
561 HandleStatusCommand); 732 HandleStatusCommand);
733
734 MainConsole.Instance.Commands.AddCommand(
735 "Debug",
736 false,
737 "debug lludp toggle agentupdate",
738 "debug lludp toggle agentupdate",
739 "Toggle whether agentupdate packets are processed or simply discarded.",
740 HandleAgentUpdateCommand);
741 }
742
743 private void HandlePacketCommand(string module, string[] args)
744 {
745 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
746 return;
747
748 bool setAsDefaultLevel = false;
749 OptionSet optionSet = new OptionSet().Add("default", o => setAsDefaultLevel = o != null);
750 List<string> filteredArgs = optionSet.Parse(args);
751
752 string name = null;
753
754 if (filteredArgs.Count == 6)
755 {
756 if (!setAsDefaultLevel)
757 {
758 name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]);
759 }
760 else
761 {
762 MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default logging level");
763 return;
764 }
765 }
766
767 if (filteredArgs.Count > 3)
768 {
769 int newDebug;
770 if (int.TryParse(filteredArgs[3], out newDebug))
771 {
772 if (setAsDefaultLevel)
773 {
774 DefaultClientPacketDebugLevel = newDebug;
775 MainConsole.Instance.OutputFormat(
776 "Debug packet debug for new clients set to {0} in {1}", DefaultClientPacketDebugLevel, m_scene.Name);
777 }
778 else
779 {
780 m_scene.ForEachScenePresence(sp =>
781 {
782 if (name == null || sp.Name == name)
783 {
784 MainConsole.Instance.OutputFormat(
785 "Packet debug for {0} ({1}) set to {2} in {3}",
786 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name);
787
788 sp.ControllingClient.DebugPacketLevel = newDebug;
789 }
790 });
791 }
792 }
793 else
794 {
795 MainConsole.Instance.Output("Usage: debug lludp packet [--default] 0..255 [<first-name> <last-name>]");
796 }
797 }
562 } 798 }
563 799
564 private void HandleStartCommand(string module, string[] args) 800 private void HandleStartCommand(string module, string[] args)
565 { 801 {
802 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
803 return;
804
566 if (args.Length != 4) 805 if (args.Length != 4)
567 { 806 {
568 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); 807 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
@@ -580,6 +819,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
580 819
581 private void HandleStopCommand(string module, string[] args) 820 private void HandleStopCommand(string module, string[] args)
582 { 821 {
822 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
823 return;
824
583 if (args.Length != 4) 825 if (args.Length != 4)
584 { 826 {
585 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); 827 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
@@ -597,6 +839,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
597 839
598 private void HandlePoolCommand(string module, string[] args) 840 private void HandlePoolCommand(string module, string[] args)
599 { 841 {
842 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
843 return;
844
600 if (args.Length != 4) 845 if (args.Length != 4)
601 { 846 {
602 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); 847 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
@@ -627,8 +872,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
627 } 872 }
628 } 873 }
629 874
875 bool m_discardAgentUpdates;
876
877 private void HandleAgentUpdateCommand(string module, string[] args)
878 {
879 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
880 return;
881
882 m_discardAgentUpdates = !m_discardAgentUpdates;
883
884 MainConsole.Instance.OutputFormat(
885 "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name);
886 }
887
630 private void HandleStatusCommand(string module, string[] args) 888 private void HandleStatusCommand(string module, string[] args)
631 { 889 {
890 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
891 return;
892
632 MainConsole.Instance.OutputFormat( 893 MainConsole.Instance.OutputFormat(
633 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); 894 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled");
634 895
@@ -636,6 +897,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
636 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); 897 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
637 898
638 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); 899 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off");
900
901 MainConsole.Instance.OutputFormat(
902 "Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel);
639 } 903 }
640 904
641 public bool HandlesRegion(Location x) 905 public bool HandlesRegion(Location x)
@@ -643,44 +907,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP
643 return x == m_location; 907 return x == m_location;
644 } 908 }
645 909
646 public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) 910// public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
647 { 911// {
648 // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way 912// // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way
649 if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting) 913// if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting)
650 allowSplitting = false; 914// allowSplitting = false;
651 915//
652 if (allowSplitting && packet.HasVariableBlocks) 916// if (allowSplitting && packet.HasVariableBlocks)
653 { 917// {
654 byte[][] datas = packet.ToBytesMultiple(); 918// byte[][] datas = packet.ToBytesMultiple();
655 int packetCount = datas.Length; 919// int packetCount = datas.Length;
656 920//
657 if (packetCount < 1) 921// if (packetCount < 1)
658 m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length); 922// m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length);
659 923//
660 for (int i = 0; i < packetCount; i++) 924// for (int i = 0; i < packetCount; i++)
661 { 925// {
662 byte[] data = datas[i]; 926// byte[] data = datas[i];
663 m_scene.ForEachClient( 927// m_scene.ForEachClient(
664 delegate(IClientAPI client) 928// delegate(IClientAPI client)
665 { 929// {
666 if (client is LLClientView) 930// if (client is LLClientView)
667 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); 931// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
668 } 932// }
669 ); 933// );
670 } 934// }
671 } 935// }
672 else 936// else
673 { 937// {
674 byte[] data = packet.ToBytes(); 938// byte[] data = packet.ToBytes();
675 m_scene.ForEachClient( 939// m_scene.ForEachClient(
676 delegate(IClientAPI client) 940// delegate(IClientAPI client)
677 { 941// {
678 if (client is LLClientView) 942// if (client is LLClientView)
679 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); 943// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
680 } 944// }
681 ); 945// );
682 } 946// }
683 } 947// }
684 948
685 /// <summary> 949 /// <summary>
686 /// Start the process of sending a packet to the client. 950 /// Start the process of sending a packet to the client.
@@ -700,6 +964,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
700 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) 964 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
701 allowSplitting = false; 965 allowSplitting = false;
702 966
967 bool packetQueued = false;
968
703 if (allowSplitting && packet.HasVariableBlocks) 969 if (allowSplitting && packet.HasVariableBlocks)
704 { 970 {
705 byte[][] datas = packet.ToBytesMultiple(); 971 byte[][] datas = packet.ToBytesMultiple();
@@ -711,16 +977,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
711 for (int i = 0; i < packetCount; i++) 977 for (int i = 0; i < packetCount; i++)
712 { 978 {
713 byte[] data = datas[i]; 979 byte[] data = datas[i];
714 SendPacketData(udpClient, data, packet.Type, category, method); 980
981 if (!SendPacketData(udpClient, data, packet.Type, category, method))
982 packetQueued = true;
715 } 983 }
716 } 984 }
717 else 985 else
718 { 986 {
719 byte[] data = packet.ToBytes(); 987 byte[] data = packet.ToBytes();
720 SendPacketData(udpClient, data, packet.Type, category, method); 988 packetQueued = SendPacketData(udpClient, data, packet.Type, category, method);
721 } 989 }
722 990
723 PacketPool.Instance.ReturnPacket(packet); 991 PacketPool.Instance.ReturnPacket(packet);
992
993 if (packetQueued)
994 m_dataPresentEvent.Set();
724 } 995 }
725 996
726 /// <summary> 997 /// <summary>
@@ -734,7 +1005,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
734 /// The method to call if the packet is not acked by the client. If null, then a standard 1005 /// The method to call if the packet is not acked by the client. If null, then a standard
735 /// resend of the packet is done. 1006 /// resend of the packet is done.
736 /// </param> 1007 /// </param>
737 public void SendPacketData( 1008 /// <returns>true if the data was sent immediately, false if it was queued for sending</returns>
1009 public bool SendPacketData(
738 LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method) 1010 LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
739 { 1011 {
740 int dataLength = data.Length; 1012 int dataLength = data.Length;
@@ -807,7 +1079,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
807 // packet so that it isn't sent before a queued update packet. 1079 // packet so that it isn't sent before a queued update packet.
808 bool requestQueue = type == PacketType.KillObject; 1080 bool requestQueue = type == PacketType.KillObject;
809 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority)) 1081 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority))
1082 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue))
1083 {
810 SendPacketFinal(outgoingPacket); 1084 SendPacketFinal(outgoingPacket);
1085 return true;
1086 }
1087
1088 return false;
811 1089
812 #endregion Queue or Send 1090 #endregion Queue or Send
813 } 1091 }
@@ -883,7 +1161,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
883 // Fire this out on a different thread so that we don't hold up outgoing packet processing for 1161 // Fire this out on a different thread so that we don't hold up outgoing packet processing for
884 // everybody else if this is being called due to an ack timeout. 1162 // everybody else if this is being called due to an ack timeout.
885 // This is the same as processing as the async process of a logout request. 1163 // This is the same as processing as the async process of a logout request.
886 Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); 1164 Util.FireAndForget(o => DeactivateClientDueToTimeout(client, timeoutTicks));
887 1165
888 return; 1166 return;
889 } 1167 }
@@ -988,6 +1266,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
988 else 1266 else
989 { 1267 {
990 Interlocked.Increment(ref udpClient.PacketsResent); 1268 Interlocked.Increment(ref udpClient.PacketsResent);
1269
1270 // We're not going to worry about interlock yet since its not currently critical that this total count
1271 // is 100% correct
1272 PacketsResentCount++;
991 } 1273 }
992 1274
993 #endregion Sequence Number Assignment 1275 #endregion Sequence Number Assignment
@@ -995,6 +1277,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
995 // Stats tracking 1277 // Stats tracking
996 Interlocked.Increment(ref udpClient.PacketsSent); 1278 Interlocked.Increment(ref udpClient.PacketsSent);
997 1279
1280 // We're not going to worry about interlock yet since its not currently critical that this total count
1281 // is 100% correct
1282 PacketsSentCount++;
1283
998 // Put the UDP payload on the wire 1284 // Put the UDP payload on the wire
999 AsyncBeginSend(buffer); 1285 AsyncBeginSend(buffer);
1000 1286
@@ -1002,6 +1288,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1002 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; 1288 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
1003 } 1289 }
1004 1290
1291 private void RecordMalformedInboundPacket(IPEndPoint endPoint)
1292 {
1293// if (m_malformedCount < 100)
1294// m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1295
1296 IncomingMalformedPacketCount++;
1297
1298 if ((IncomingMalformedPacketCount % 10000) == 0)
1299 m_log.WarnFormat(
1300 "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}",
1301 IncomingMalformedPacketCount, endPoint);
1302 }
1303
1005 public override void PacketReceived(UDPPacketBuffer buffer) 1304 public override void PacketReceived(UDPPacketBuffer buffer)
1006 { 1305 {
1007 // Debugging/Profiling 1306 // Debugging/Profiling
@@ -1023,6 +1322,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1023// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", 1322// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
1024// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 1323// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1025 1324
1325 RecordMalformedInboundPacket(endPoint);
1326
1026 return; // Drop undersized packet 1327 return; // Drop undersized packet
1027 } 1328 }
1028 1329
@@ -1041,6 +1342,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1041// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", 1342// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}",
1042// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 1343// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1043 1344
1345 RecordMalformedInboundPacket(endPoint);
1346
1044 return; // Malformed header 1347 return; // Malformed header
1045 } 1348 }
1046 1349
@@ -1056,34 +1359,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1056 // Only allocate a buffer for zerodecoding if the packet is zerocoded 1359 // Only allocate a buffer for zerodecoding if the packet is zerocoded
1057 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 1360 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
1058 } 1361 }
1059 catch (MalformedDataException)
1060 {
1061 }
1062 catch (IndexOutOfRangeException)
1063 {
1064// m_log.WarnFormat(
1065// "[LLUDPSERVER]: Dropping short packet received from {0} in {1}",
1066// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1067
1068 return; // Drop short packet
1069 }
1070 catch (Exception e) 1362 catch (Exception e)
1071 { 1363 {
1072 if (m_malformedCount < 100) 1364 if (IncomingMalformedPacketCount < 100)
1073 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); 1365 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1074
1075 m_malformedCount++;
1076
1077 if ((m_malformedCount % 100000) == 0)
1078 m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
1079 } 1366 }
1080 1367
1081 // Fail-safe check 1368 // Fail-safe check
1082 if (packet == null) 1369 if (packet == null)
1083 { 1370 {
1084 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:", 1371 if (IncomingMalformedPacketCount < 100)
1085 buffer.DataLength, buffer.RemoteEndPoint); 1372 {
1086 m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); 1373 m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:",
1374 buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
1375 }
1376
1377 RecordMalformedInboundPacket(endPoint);
1378
1087 return; 1379 return;
1088 } 1380 }
1089 1381
@@ -1127,12 +1419,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1127 queue.Enqueue(buffer); 1419 queue.Enqueue(buffer);
1128 return; 1420 return;
1129 } 1421 }
1422 else if (packet.Type == PacketType.CompleteAgentMovement)
1423 {
1424 // Send ack straight away to let the viewer know that we got it.
1425 SendAckImmediate(endPoint, packet.Header.Sequence);
1426
1427 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1428 // buffer.
1429 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1430
1431 Util.FireAndForget(HandleCompleteMovementIntoRegion, array);
1432
1433 return;
1434 }
1130 } 1435 }
1131 1436
1132 // Determine which agent this packet came from 1437 // Determine which agent this packet came from
1133 if (client == null || !(client is LLClientView)) 1438 if (client == null || !(client is LLClientView))
1134 { 1439 {
1135 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1440 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1441
1442 IncomingOrphanedPacketCount++;
1443
1444 if ((IncomingOrphanedPacketCount % 10000) == 0)
1445 m_log.WarnFormat(
1446 "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}",
1447 IncomingOrphanedPacketCount, endPoint);
1448
1136 return; 1449 return;
1137 } 1450 }
1138 1451
@@ -1211,6 +1524,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1211 1524
1212 #region Incoming Packet Accounting 1525 #region Incoming Packet Accounting
1213 1526
1527 // We're not going to worry about interlock yet since its not currently critical that this total count
1528 // is 100% correct
1529 if (packet.Header.Resent)
1530 IncomingPacketsResentCount++;
1531
1214 // Check the archive of received reliable packet IDs to see whether we already received this packet 1532 // Check the archive of received reliable packet IDs to see whether we already received this packet
1215 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence)) 1533 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
1216 { 1534 {
@@ -1233,6 +1551,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1233 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); 1551 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
1234 #endregion BinaryStats 1552 #endregion BinaryStats
1235 1553
1554 if (packet.Type == PacketType.AgentUpdate)
1555 {
1556 if (m_discardAgentUpdates)
1557 return;
1558
1559 ((LLClientView)client).TotalAgentUpdates++;
1560
1561 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
1562
1563 LLClientView llClient = client as LLClientView;
1564 if (agentUpdate.AgentData.SessionID != client.SessionId
1565 || agentUpdate.AgentData.AgentID != client.AgentId
1566 || !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) )
1567 {
1568 PacketPool.Instance.ReturnPacket(packet);
1569 return;
1570 }
1571 }
1572
1236 #region Ping Check Handling 1573 #region Ping Check Handling
1237 1574
1238 if (packet.Type == PacketType.StartPingCheck) 1575 if (packet.Type == PacketType.StartPingCheck)
@@ -1421,7 +1758,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1421 1758
1422 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1759 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1423 if (client != null) 1760 if (client != null)
1424 client.SceneAgent.SendInitialDataToMe(); 1761 {
1762 AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1763 bool tp = (aCircuit.teleportFlags > 0);
1764 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from
1765 if (!tp)
1766 client.SceneAgent.SendInitialDataToMe();
1767 }
1425 1768
1426 // Now we know we can handle more data 1769 // Now we know we can handle more data
1427 Thread.Sleep(200); 1770 Thread.Sleep(200);
@@ -1476,6 +1819,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1476 } 1819 }
1477 } 1820 }
1478 1821
1822 private void HandleCompleteMovementIntoRegion(object o)
1823 {
1824 IPEndPoint endPoint = null;
1825 IClientAPI client = null;
1826
1827 try
1828 {
1829 object[] array = (object[])o;
1830 endPoint = (IPEndPoint)array[0];
1831 CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1];
1832
1833 m_log.DebugFormat(
1834 "[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, m_scene.Name);
1835
1836 // Determine which agent this packet came from
1837 // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination
1838 // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode
1839 // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these
1840 // packets asynchronously, we need to account for this thread proceeding more quickly than the
1841 // UseCircuitCode thread.
1842 int count = 40;
1843 while (count-- > 0)
1844 {
1845 if (m_scene.TryGetClient(endPoint, out client))
1846 {
1847 if (!client.IsActive)
1848 {
1849 // This check exists to catch a condition where the client has been closed by another thread
1850 // but has not yet been removed from the client manager (and possibly a new connection has
1851 // not yet been established).
1852 m_log.DebugFormat(
1853 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.",
1854 endPoint, client.Name, m_scene.Name);
1855 }
1856 else if (client.SceneAgent == null)
1857 {
1858 // This check exists to catch a condition where the new client has been added to the client
1859 // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too
1860 // eager, then the new ScenePresence may not have registered a listener for this messsage
1861 // before we try to process it.
1862 // XXX: A better long term fix may be to add the SceneAgent before the client is added to
1863 // the client manager
1864 m_log.DebugFormat(
1865 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.",
1866 endPoint, client.Name, m_scene.Name);
1867 }
1868 else
1869 {
1870 break;
1871 }
1872 }
1873 else
1874 {
1875 m_log.DebugFormat(
1876 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.",
1877 endPoint, m_scene.Name);
1878 }
1879
1880 Thread.Sleep(200);
1881 }
1882
1883 if (client == null)
1884 {
1885 m_log.DebugFormat(
1886 "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.",
1887 endPoint, m_scene.Name);
1888
1889 return;
1890 }
1891 else if (!client.IsActive || client.SceneAgent == null)
1892 {
1893 // This check exists to catch a condition where the client has been closed by another thread
1894 // but has not yet been removed from the client manager.
1895 // The packet could be simply ignored but it is useful to know if this condition occurred for other debugging
1896 // purposes.
1897 m_log.DebugFormat(
1898 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.",
1899 endPoint, client.Name, m_scene.Name);
1900
1901 return;
1902 }
1903
1904 IncomingPacket incomingPacket1;
1905
1906 // Inbox insertion
1907 if (UsePools)
1908 {
1909 incomingPacket1 = m_incomingPacketPool.GetObject();
1910 incomingPacket1.Client = (LLClientView)client;
1911 incomingPacket1.Packet = packet;
1912 }
1913 else
1914 {
1915 incomingPacket1 = new IncomingPacket((LLClientView)client, packet);
1916 }
1917
1918 packetInbox.Enqueue(incomingPacket1);
1919 }
1920 catch (Exception e)
1921 {
1922 m_log.ErrorFormat(
1923 "[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1924 endPoint != null ? endPoint.ToString() : "n/a",
1925 client != null ? client.Name : "unknown",
1926 client != null ? client.AgentId.ToString() : "unknown",
1927 e.Message,
1928 e.StackTrace);
1929 }
1930 }
1931
1479 /// <summary> 1932 /// <summary>
1480 /// Send an ack immediately to the given endpoint. 1933 /// Send an ack immediately to the given endpoint.
1481 /// </summary> 1934 /// </summary>
@@ -1544,6 +1997,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1544 1997
1545 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 1998 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1546 client.OnLogout += LogoutHandler; 1999 client.OnLogout += LogoutHandler;
2000 client.DebugPacketLevel = DefaultClientPacketDebugLevel;
1547 2001
1548 ((LLClientView)client).DisableFacelights = m_disableFacelights; 2002 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1549 2003
@@ -1562,21 +2016,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1562 /// regular client pings. 2016 /// regular client pings.
1563 /// </remarks> 2017 /// </remarks>
1564 /// <param name='client'></param> 2018 /// <param name='client'></param>
1565 private void DeactivateClientDueToTimeout(LLClientView client) 2019 /// <param name='timeoutTicks'></param>
2020 private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks)
1566 { 2021 {
1567 lock (client.CloseSyncLock) 2022 lock (client.CloseSyncLock)
1568 { 2023 {
2024 ClientLogoutsDueToNoReceives++;
2025
1569 m_log.WarnFormat( 2026 m_log.WarnFormat(
1570 "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", 2027 "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.",
1571 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName); 2028 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, m_scene.Name);
1572
1573 StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
1574 2029
1575 if (!client.SceneAgent.IsChildAgent) 2030 if (!client.SceneAgent.IsChildAgent)
1576 client.Kick("Simulator logged you out due to connection timeout"); 2031 client.Kick("Simulator logged you out due to connection timeout.");
1577
1578 client.CloseWithoutChecks(true);
1579 } 2032 }
2033
2034 m_scene.CloseAgent(client.AgentId, true);
1580 } 2035 }
1581 2036
1582 private void IncomingPacketHandler() 2037 private void IncomingPacketHandler()
@@ -1592,6 +2047,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1592 { 2047 {
1593 IncomingPacket incomingPacket = null; 2048 IncomingPacket incomingPacket = null;
1594 2049
2050 /*
1595 // HACK: This is a test to try and rate limit packet handling on Mono. 2051 // HACK: This is a test to try and rate limit packet handling on Mono.
1596 // If it works, a more elegant solution can be devised 2052 // If it works, a more elegant solution can be devised
1597 if (Util.FireAndForgetCount() < 2) 2053 if (Util.FireAndForgetCount() < 2)
@@ -1599,6 +2055,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1599 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); 2055 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping");
1600 Thread.Sleep(30); 2056 Thread.Sleep(30);
1601 } 2057 }
2058 */
1602 2059
1603 if (packetInbox.Dequeue(100, ref incomingPacket)) 2060 if (packetInbox.Dequeue(100, ref incomingPacket))
1604 { 2061 {
@@ -1694,8 +2151,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1694 2151
1695 // If nothing was sent, sleep for the minimum amount of time before a 2152 // If nothing was sent, sleep for the minimum amount of time before a
1696 // token bucket could get more tokens 2153 // token bucket could get more tokens
2154 //if (!m_packetSent)
2155 // Thread.Sleep((int)TickCountResolution);
2156 //
2157 // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with
2158 // modern mono it reduces CPU base load since there is no more continuous polling.
1697 if (!m_packetSent) 2159 if (!m_packetSent)
1698 Thread.Sleep((int)TickCountResolution); 2160 m_dataPresentEvent.WaitOne(100);
1699 2161
1700 Watchdog.UpdateThread(); 2162 Watchdog.UpdateThread();
1701 } 2163 }
@@ -1912,7 +2374,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1912 if (!client.IsLoggingOut) 2374 if (!client.IsLoggingOut)
1913 { 2375 {
1914 client.IsLoggingOut = true; 2376 client.IsLoggingOut = true;
1915 client.Close(false, false); 2377 m_scene.CloseAgent(client.AgentId, false);
1916 } 2378 }
1917 } 2379 }
1918 } 2380 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index 7035e38..881e768 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -78,6 +78,36 @@ namespace OpenMetaverse
78 public bool IsRunningOutbound { get; private set; } 78 public bool IsRunningOutbound { get; private set; }
79 79
80 /// <summary> 80 /// <summary>
81 /// Number of UDP receives.
82 /// </summary>
83 public int UdpReceives { get; private set; }
84
85 /// <summary>
86 /// Number of UDP sends
87 /// </summary>
88 public int UdpSends { get; private set; }
89
90 /// <summary>
91 /// Number of receives over which to establish a receive time average.
92 /// </summary>
93 private readonly static int s_receiveTimeSamples = 500;
94
95 /// <summary>
96 /// Current number of samples taken to establish a receive time average.
97 /// </summary>
98 private int m_currentReceiveTimeSamples;
99
100 /// <summary>
101 /// Cumulative receive time for the sample so far.
102 /// </summary>
103 private int m_receiveTicksInCurrentSamplePeriod;
104
105 /// <summary>
106 /// The average time taken for each require receive in the last sample.
107 /// </summary>
108 public float AverageReceiveTicksForLastSamplePeriod { get; private set; }
109
110 /// <summary>
81 /// Default constructor 111 /// Default constructor
82 /// </summary> 112 /// </summary>
83 /// <param name="bindAddress">Local IP address to bind the server to</param> 113 /// <param name="bindAddress">Local IP address to bind the server to</param>
@@ -111,6 +141,8 @@ namespace OpenMetaverse
111 141
112 if (!IsRunningInbound) 142 if (!IsRunningInbound)
113 { 143 {
144 m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop");
145
114 const int SIO_UDP_CONNRESET = -1744830452; 146 const int SIO_UDP_CONNRESET = -1744830452;
115 147
116 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); 148 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
@@ -151,6 +183,8 @@ namespace OpenMetaverse
151 /// </summary> 183 /// </summary>
152 public void StartOutbound() 184 public void StartOutbound()
153 { 185 {
186 m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop");
187
154 IsRunningOutbound = true; 188 IsRunningOutbound = true;
155 } 189 }
156 190
@@ -158,10 +192,8 @@ namespace OpenMetaverse
158 { 192 {
159 if (IsRunningInbound) 193 if (IsRunningInbound)
160 { 194 {
161 // wait indefinitely for a writer lock. Once this is called, the .NET runtime 195 m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop");
162 // will deny any more reader locks, in effect blocking all other send/receive 196
163 // threads. Once we have the lock, we set IsRunningInbound = false to inform the other
164 // threads that the socket is closed.
165 IsRunningInbound = false; 197 IsRunningInbound = false;
166 m_udpSocket.Close(); 198 m_udpSocket.Close();
167 } 199 }
@@ -169,6 +201,8 @@ namespace OpenMetaverse
169 201
170 public void StopOutbound() 202 public void StopOutbound()
171 { 203 {
204 m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop");
205
172 IsRunningOutbound = false; 206 IsRunningOutbound = false;
173 } 207 }
174 208
@@ -257,7 +291,16 @@ namespace OpenMetaverse
257 m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); 291 m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort);
258 } 292 }
259 } 293 }
260 catch (ObjectDisposedException) { } 294 catch (ObjectDisposedException e)
295 {
296 m_log.Error(
297 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
298 }
299 catch (Exception e)
300 {
301 m_log.Error(
302 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
303 }
261 } 304 }
262 } 305 }
263 306
@@ -267,17 +310,21 @@ namespace OpenMetaverse
267 // to AsyncBeginReceive 310 // to AsyncBeginReceive
268 if (IsRunningInbound) 311 if (IsRunningInbound)
269 { 312 {
313 UdpReceives++;
314
270 // Asynchronous mode will start another receive before the 315 // Asynchronous mode will start another receive before the
271 // callback for this packet is even fired. Very parallel :-) 316 // callback for this packet is even fired. Very parallel :-)
272 if (m_asyncPacketHandling) 317 if (m_asyncPacketHandling)
273 AsyncBeginReceive(); 318 AsyncBeginReceive();
274 319
275 // get the buffer that was created in AsyncBeginReceive
276 // this is the received data
277 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
278
279 try 320 try
280 { 321 {
322 // get the buffer that was created in AsyncBeginReceive
323 // this is the received data
324 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
325
326 int startTick = Util.EnvironmentTickCount();
327
281 // get the length of data actually read from the socket, store it with the 328 // get the length of data actually read from the socket, store it with the
282 // buffer 329 // buffer
283 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); 330 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
@@ -285,9 +332,42 @@ namespace OpenMetaverse
285 // call the abstract method PacketReceived(), passing the buffer that 332 // call the abstract method PacketReceived(), passing the buffer that
286 // has just been filled from the socket read. 333 // has just been filled from the socket read.
287 PacketReceived(buffer); 334 PacketReceived(buffer);
335
336 // If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler)
337 // then a particular stat may be inaccurate due to a race condition. We won't worry about this
338 // since this should be rare and won't cause a runtime problem.
339 if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
340 {
341 AverageReceiveTicksForLastSamplePeriod
342 = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
343
344 m_receiveTicksInCurrentSamplePeriod = 0;
345 m_currentReceiveTimeSamples = 0;
346 }
347 else
348 {
349 m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick);
350 m_currentReceiveTimeSamples++;
351 }
352 }
353 catch (SocketException se)
354 {
355 m_log.Error(
356 string.Format(
357 "[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}. Exception ",
358 UdpReceives, se.ErrorCode),
359 se);
360 }
361 catch (ObjectDisposedException e)
362 {
363 m_log.Error(
364 string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
365 }
366 catch (Exception e)
367 {
368 m_log.Error(
369 string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
288 } 370 }
289 catch (SocketException) { }
290 catch (ObjectDisposedException) { }
291 finally 371 finally
292 { 372 {
293// if (UsePools) 373// if (UsePools)
@@ -298,14 +378,13 @@ namespace OpenMetaverse
298 if (!m_asyncPacketHandling) 378 if (!m_asyncPacketHandling)
299 AsyncBeginReceive(); 379 AsyncBeginReceive();
300 } 380 }
301
302 } 381 }
303 } 382 }
304 383
305 public void AsyncBeginSend(UDPPacketBuffer buf) 384 public void AsyncBeginSend(UDPPacketBuffer buf)
306 { 385 {
307 if (IsRunningOutbound) 386// if (IsRunningOutbound)
308 { 387// {
309 try 388 try
310 { 389 {
311 m_udpSocket.BeginSendTo( 390 m_udpSocket.BeginSendTo(
@@ -319,7 +398,7 @@ namespace OpenMetaverse
319 } 398 }
320 catch (SocketException) { } 399 catch (SocketException) { }
321 catch (ObjectDisposedException) { } 400 catch (ObjectDisposedException) { }
322 } 401// }
323 } 402 }
324 403
325 void AsyncEndSend(IAsyncResult result) 404 void AsyncEndSend(IAsyncResult result)
@@ -328,6 +407,8 @@ namespace OpenMetaverse
328 { 407 {
329// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; 408// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
330 m_udpSocket.EndSendTo(result); 409 m_udpSocket.EndSendTo(result);
410
411 UdpSends++;
331 } 412 }
332 catch (SocketException) { } 413 catch (SocketException) { }
333 catch (ObjectDisposedException) { } 414 catch (ObjectDisposedException) { }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
index 1fdc410..5a2bcee 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -145,39 +145,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
145 return packet; 145 return packet;
146 } 146 }
147 147
148 // private byte[] decoded_header = new byte[10];
149 private static PacketType GetType(byte[] bytes) 148 private static PacketType GetType(byte[] bytes)
150 { 149 {
151 byte[] decoded_header = new byte[10 + 8];
152 ushort id; 150 ushort id;
153 PacketFrequency freq; 151 PacketFrequency freq;
152 bool isZeroCoded = (bytes[0] & Helpers.MSG_ZEROCODED) != 0;
154 153
155 if ((bytes[0] & Helpers.MSG_ZEROCODED) != 0) 154 if (bytes[6] == 0xFF)
156 { 155 {
157 Helpers.ZeroDecode(bytes, 16, decoded_header); 156 if (bytes[7] == 0xFF)
158 }
159 else
160 {
161 Buffer.BlockCopy(bytes, 0, decoded_header, 0, 10);
162 }
163
164 if (decoded_header[6] == 0xFF)
165 {
166 if (decoded_header[7] == 0xFF)
167 { 157 {
168 id = (ushort) ((decoded_header[8] << 8) + decoded_header[9]);
169 freq = PacketFrequency.Low; 158 freq = PacketFrequency.Low;
159 if (isZeroCoded && bytes[8] == 0)
160 id = bytes[10];
161 else
162 id = (ushort)((bytes[8] << 8) + bytes[9]);
170 } 163 }
171 else 164 else
172 { 165 {
173 id = decoded_header[7];
174 freq = PacketFrequency.Medium; 166 freq = PacketFrequency.Medium;
167 id = bytes[7];
175 } 168 }
176 } 169 }
177 else 170 else
178 { 171 {
179 id = decoded_header[6];
180 freq = PacketFrequency.High; 172 freq = PacketFrequency.High;
173 id = bytes[6];
181 } 174 }
182 175
183 return Packet.GetType(id, freq); 176 return Packet.GetType(id, freq);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
index 98ef72f..f8d0c02 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.6.*")] 32[assembly: AssemblyVersion("0.8.0.*")]
33 33
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
index 556df30..9700224 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
@@ -33,6 +33,7 @@ using NUnit.Framework;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenMetaverse.Packets; 34using OpenMetaverse.Packets;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
37using OpenSim.Tests.Common; 38using OpenSim.Tests.Common;
38using OpenSim.Tests.Common.Mock; 39using OpenSim.Tests.Common.Mock;
@@ -69,6 +70,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
69 { 70 {
70 base.SetUp(); 71 base.SetUp();
71 m_scene = new SceneHelpers().SetupScene(); 72 m_scene = new SceneHelpers().SetupScene();
73 StatsManager.SimExtraStats = new SimExtraStatsCollector();
72 } 74 }
73 75
74 /// <summary> 76 /// <summary>
@@ -198,7 +200,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
198 public void TestLogoutClientDueToAck() 200 public void TestLogoutClientDueToAck()
199 { 201 {
200 TestHelpers.InMethod(); 202 TestHelpers.InMethod();
201// TestHelpers.EnableLogging(); 203 TestHelpers.EnableLogging();
202 204
203 IniConfigSource ics = new IniConfigSource(); 205 IniConfigSource ics = new IniConfigSource();
204 IConfig config = ics.AddConfig("ClientStack.LindenUDP"); 206 IConfig config = ics.AddConfig("ClientStack.LindenUDP");
@@ -210,8 +212,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
210 212
211 ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); 213 ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID);
212 Assert.That(spAfterAckTimeout, Is.Null); 214 Assert.That(spAfterAckTimeout, Is.Null);
213
214// TestHelpers.DisableLogging();
215 } 215 }
216 216
217// /// <summary> 217// /// <summary>
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
index 7d9f581..575e54c 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
@@ -29,6 +29,7 @@ using System;
29using System.IO; 29using System.IO;
30using System.Net; 30using System.Net;
31using System.Reflection; 31using System.Reflection;
32using System.Threading;
32using log4net.Config; 33using log4net.Config;
33using Nini.Config; 34using Nini.Config;
34using NUnit.Framework; 35using NUnit.Framework;
@@ -53,6 +54,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
53 [TestFixtureSetUp] 54 [TestFixtureSetUp]
54 public void FixtureInit() 55 public void FixtureInit()
55 { 56 {
57 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
58 Util.FireAndForgetMethod = FireAndForgetMethod.None;
59
56 using ( 60 using (
57 Stream resource 61 Stream resource
58 = GetType().Assembly.GetManifestResourceStream( 62 = GetType().Assembly.GetManifestResourceStream(
@@ -72,9 +76,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
72 } 76 }
73 } 77 }
74 78
79 [TestFixtureTearDown]
80 public void TearDown()
81 {
82 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
83 // threads. Possibly, later tests should be rewritten not to worry about such things.
84 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
85 }
86
75 [SetUp] 87 [SetUp]
76 public void SetUp() 88 public override void SetUp()
77 { 89 {
90 base.SetUp();
91
78 UUID userId = TestHelpers.ParseTail(0x3); 92 UUID userId = TestHelpers.ParseTail(0x3);
79 93
80 J2KDecoderModule j2kdm = new J2KDecoderModule(); 94 J2KDecoderModule j2kdm = new J2KDecoderModule();
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
index 119a677..e2178e5 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
@@ -52,17 +52,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
52 public override void Update(int frames) {} 52 public override void Update(int frames) {}
53 public override void LoadWorldMap() {} 53 public override void LoadWorldMap() {}
54 54
55 public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type) 55 public override ISceneAgent AddNewAgent(IClientAPI client, PresenceType type)
56 { 56 {
57 client.OnObjectName += RecordObjectNameCall; 57 client.OnObjectName += RecordObjectNameCall;
58 58
59 // FIXME 59 // FIXME
60 return null; 60 return null;
61 } 61 }
62 62
63 public override void RemoveClient(UUID agentID, bool someReason) {} 63 public override bool CloseAgent(UUID agentID, bool force) { return true; }
64// public override void CloseAllAgents(uint circuitcode) {} 64
65 public override bool CheckClient(UUID clientId, IPEndPoint endPoint) { return true; } 65 public override bool CheckClient(UUID clientId, IPEndPoint endPoint) { return true; }
66
66 public override void OtherRegionUp(GridRegion otherRegion) { } 67 public override void OtherRegionUp(GridRegion otherRegion) { }
67 68
68 public override bool TryGetScenePresence(UUID uuid, out ScenePresence sp) { sp = null; return false; } 69 public override bool TryGetScenePresence(UUID uuid, out ScenePresence sp) { sp = null; return false; }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
index c9aac0b..e5bae6e 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
@@ -59,6 +59,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
59 /// <summary>Flag used to enable adaptive throttles</summary> 59 /// <summary>Flag used to enable adaptive throttles</summary>
60 public bool AdaptiveThrottlesEnabled; 60 public bool AdaptiveThrottlesEnabled;
61 61
62 /// <summary>Amount of the texture throttle to steal for the task throttle</summary>
63 public double CannibalizeTextureRate;
64
62 /// <summary> 65 /// <summary>
63 /// Default constructor 66 /// Default constructor
64 /// </summary> 67 /// </summary>
@@ -80,6 +83,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
80 Total = throttleConfig.GetInt("client_throttle_max_bps", 0); 83 Total = throttleConfig.GetInt("client_throttle_max_bps", 0);
81 84
82 AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); 85 AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false);
86
87 CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f);
88 CannibalizeTextureRate = Util.Clamp<double>(CannibalizeTextureRate,0.0, 0.9);
83 } 89 }
84 catch (Exception) { } 90 catch (Exception) { }
85 } 91 }