aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/IClientNetworkServer.cs15
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs139
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs23
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs113
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs6
-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/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.cs104
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs4
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs644
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs7
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs96
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs436
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs72
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs25
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs6
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs16
20 files changed, 1315 insertions, 489 deletions
diff --git a/OpenSim/Region/ClientStack/IClientNetworkServer.cs b/OpenSim/Region/ClientStack/IClientNetworkServer.cs
index 54a441b..bb7e6d0 100644
--- a/OpenSim/Region/ClientStack/IClientNetworkServer.cs
+++ b/OpenSim/Region/ClientStack/IClientNetworkServer.cs
@@ -38,11 +38,22 @@ namespace OpenSim.Region.ClientStack
38 IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, 38 IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource,
39 AgentCircuitManager authenticateClass); 39 AgentCircuitManager authenticateClass);
40 40
41 void NetworkStop();
42 bool HandlesRegion(Location x); 41 bool HandlesRegion(Location x);
43 void AddScene(IScene x);
44 42
43 /// <summary>
44 /// Add the given scene to be handled by this IClientNetworkServer.
45 /// </summary>
46 /// <param name='scene'></param>
47 void AddScene(IScene scene);
48
49 /// <summary>
50 /// Start sending and receiving data.
51 /// </summary>
45 void Start(); 52 void Start();
53
54 /// <summary>
55 /// Stop sending and receiving data.
56 /// </summary>
46 void Stop(); 57 void Stop();
47 } 58 }
48} 59}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs
new file mode 100644
index 0000000..10a4753
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs
@@ -0,0 +1,139 @@
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
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AvatarPickerSearchModule")]
54 public class AvatarPickerSearchModule : INonSharedRegionModule
55 {
56 private static readonly ILog m_log =
57 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58
59 private Scene m_scene;
60 private IPeople m_People;
61 private bool m_Enabled = false;
62
63 private string m_URL;
64
65 #region ISharedRegionModule Members
66
67 public void Initialise(IConfigSource source)
68 {
69 IConfig config = source.Configs["ClientStack.LindenCaps"];
70 if (config == null)
71 return;
72
73 m_URL = config.GetString("Cap_AvatarPickerSearch", string.Empty);
74 // Cap doesn't exist
75 if (m_URL != string.Empty)
76 m_Enabled = true;
77 }
78
79 public void AddRegion(Scene s)
80 {
81 if (!m_Enabled)
82 return;
83
84 m_scene = s;
85 }
86
87 public void RemoveRegion(Scene s)
88 {
89 if (!m_Enabled)
90 return;
91
92 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
93 m_scene = null;
94 }
95
96 public void RegionLoaded(Scene s)
97 {
98 if (!m_Enabled)
99 return;
100
101 m_People = m_scene.RequestModuleInterface<IPeople>();
102 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
103 }
104
105 public void PostInitialise()
106 {
107 }
108
109 public void Close() { }
110
111 public string Name { get { return "AvatarPickerSearchModule"; } }
112
113 public Type ReplaceableInterface
114 {
115 get { return null; }
116 }
117
118 #endregion
119
120 public void RegisterCaps(UUID agentID, Caps caps)
121 {
122 UUID capID = UUID.Random();
123
124 if (m_URL == "localhost")
125 {
126// m_log.DebugFormat("[AVATAR PICKER SEARCH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
127 caps.RegisterHandler(
128 "AvatarPickerSearch",
129 new AvatarPickerSearchHandler("/CAPS/" + capID + "/", m_People, "AvatarPickerSearch", "Search for avatars by name"));
130 }
131 else
132 {
133 // m_log.DebugFormat("[AVATAR PICKER SEARCH]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName);
134 caps.RegisterHandler("AvatarPickerSearch", m_URL);
135 }
136 }
137
138 }
139}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 8241e07..762e22a 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
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
index eb40eb1..725bf06 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>
@@ -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 {
@@ -794,12 +755,12 @@ namespace OpenSim.Region.ClientStack.Linden
794 755
795 } 756 }
796 757
797 public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, 758 public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat,
798 bool isModerator, bool textMute) 759 bool isModerator, bool textMute)
799 { 760 {
800 OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, 761 OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat,
801 isModerator, textMute); 762 isModerator, textMute);
802 Enqueue(item, toAgent); 763 Enqueue(item, fromAgent);
803 //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); 764 //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item);
804 } 765 }
805 766
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
index 141af8a..b3b0b8a 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,10 +88,10 @@ 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
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/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..cf95463 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..f816ad3 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
@@ -284,47 +304,53 @@ namespace OpenSim.Region.ClientStack.Linden
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 if (m_fetchInventoryDescendents2Url == "")
308 return;
288 309
289 // Register this as a poll service 310 // Register this as a poll service
290 PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID); 311 PollServiceInventoryEventArgs args
291 312 = new PollServiceInventoryEventArgs(m_scene, "/CAPS/" + UUID.Random() + "/", agentID);
292 args.Type = PollServiceEventArgs.EventType.Inventory; 313 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 314
307 m_capsDict[agentID] = capUrl; 315 caps.RegisterPollHandler("FetchInventoryDescendents2", args);
316
317// MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
318//
319// string hostName = m_scene.RegionInfo.ExternalHostName;
320// uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
321// string protocol = "http";
322//
323// if (MainServer.Instance.UseSSL)
324// {
325// hostName = MainServer.Instance.SSLCommonName;
326// port = MainServer.Instance.SSLPort;
327// protocol = "https";
328// }
329//
330// caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
308 } 331 }
309 332
310 private void DeregisterCaps(UUID agentID, Caps caps) 333// private void DeregisterCaps(UUID agentID, Caps caps)
311 { 334// {
312 string capUrl; 335// string capUrl;
313 336//
314 if (m_capsDict.TryGetValue(agentID, out capUrl)) 337// if (m_capsDict.TryGetValue(agentID, out capUrl))
315 { 338// {
316 MainServer.Instance.RemoveHTTPHandler("", capUrl); 339// MainServer.Instance.RemoveHTTPHandler("", capUrl);
317 m_capsDict.Remove(agentID); 340// m_capsDict.Remove(agentID);
318 } 341// }
319 } 342// }
320 343
321 private void DoInventoryRequests() 344 private void DoInventoryRequests()
322 { 345 {
323 while (true) 346 while (true)
324 { 347 {
348 Watchdog.UpdateThread();
349
325 aPollRequest poolreq = m_queue.Dequeue(); 350 aPollRequest poolreq = m_queue.Dequeue();
326 351
327 poolreq.thepoll.Process(poolreq); 352 if (poolreq != null && poolreq.thepoll != null)
353 poolreq.thepoll.Process(poolreq);
328 } 354 }
329 } 355 }
330 } 356 }
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 f4ea975..36edd0b 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 }
@@ -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.
1214 1246
1215 OutPacket(layerpack, ThrottleOutPacketType.Task); 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.
1253
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 {
@@ -1580,7 +1631,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1580 OutPacket(pc, ThrottleOutPacketType.Unknown); 1631 OutPacket(pc, ThrottleOutPacketType.Unknown);
1581 } 1632 }
1582 1633
1583 public void SendKillObject(ulong regionHandle, List<uint> localIDs) 1634 public void SendKillObject(List<uint> localIDs)
1584 { 1635 {
1585// foreach (uint id in localIDs) 1636// foreach (uint id in localIDs)
1586// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); 1637// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
@@ -3797,6 +3848,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3797 ResendPrimUpdate(update); 3848 ResendPrimUpdate(update);
3798 } 3849 }
3799 3850
3851// OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
3852// OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>();
3853// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3854// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3855//
3856// OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3857// OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3858// OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3859// OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3860
3861
3800 private void ProcessEntityUpdates(int maxUpdates) 3862 private void ProcessEntityUpdates(int maxUpdates)
3801 { 3863 {
3802 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); 3864 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
@@ -3809,6 +3871,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3809 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); 3871 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3810 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); 3872 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3811 3873
3874// objectUpdateBlocks.Value.Clear();
3875// compressedUpdateBlocks.Value.Clear();
3876// terseUpdateBlocks.Value.Clear();
3877// terseAgentUpdateBlocks.Value.Clear();
3878// objectUpdates.Value.Clear();
3879// compressedUpdates.Value.Clear();
3880// terseUpdates.Value.Clear();
3881// terseAgentUpdates.Value.Clear();
3882
3812 // Check to see if this is a flush 3883 // Check to see if this is a flush
3813 if (maxUpdates <= 0) 3884 if (maxUpdates <= 0)
3814 { 3885 {
@@ -4137,8 +4208,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4137 4208
4138 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) 4209 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
4139 { 4210 {
4211// if (!m_udpServer.IsRunningOutbound)
4212// return;
4213
4140 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) 4214 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4141 { 4215 {
4216// if (!m_udpServer.IsRunningOutbound)
4217// return;
4218
4142 if (m_maxUpdates == 0 || m_LastQueueFill == 0) 4219 if (m_maxUpdates == 0 || m_LastQueueFill == 0)
4143 { 4220 {
4144 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; 4221 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
@@ -4164,6 +4241,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4164 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); 4241 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit);
4165 } 4242 }
4166 4243
4244 internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories)
4245 {
4246 bool hasUpdates = false;
4247
4248 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4249 {
4250 if (m_entityUpdates.Count > 0)
4251 hasUpdates = true;
4252 else if (m_entityProps.Count > 0)
4253 hasUpdates = true;
4254 }
4255
4256 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
4257 {
4258 if (ImageManager.HasUpdates())
4259 hasUpdates = true;
4260 }
4261
4262 return hasUpdates;
4263 }
4264
4167 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) 4265 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
4168 { 4266 {
4169 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); 4267 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
@@ -4874,7 +4972,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4874 4972
4875 public void SendForceClientSelectObjects(List<uint> ObjectIDs) 4973 public void SendForceClientSelectObjects(List<uint> ObjectIDs)
4876 { 4974 {
4877 m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); 4975// m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count);
4878 4976
4879 bool firstCall = true; 4977 bool firstCall = true;
4880 const int MAX_OBJECTS_PER_PACKET = 251; 4978 const int MAX_OBJECTS_PER_PACKET = 251;
@@ -5031,7 +5129,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5031 SceneObjectPart part = (SceneObjectPart)entity; 5129 SceneObjectPart part = (SceneObjectPart)entity;
5032 5130
5033 attachPoint = part.ParentGroup.AttachmentPoint; 5131 attachPoint = part.ParentGroup.AttachmentPoint;
5034 5132 attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16));
5035// m_log.DebugFormat( 5133// m_log.DebugFormat(
5036// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", 5134// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}",
5037// attachPoint, part.Name, part.LocalId, Name); 5135// attachPoint, part.Name, part.LocalId, Name);
@@ -5059,7 +5157,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5059 pos += 4; 5157 pos += 4;
5060 5158
5061 // Avatar/CollisionPlane 5159 // Avatar/CollisionPlane
5062 data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ; 5160 data[pos++] = (byte) attachPoint;
5063 if (avatar) 5161 if (avatar)
5064 { 5162 {
5065 data[pos++] = 1; 5163 data[pos++] = 1;
@@ -5384,7 +5482,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5384 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); 5482 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject);
5385 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); 5483 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject);
5386 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); 5484 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand);
5387 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply); 5485 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false);
5388 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); 5486 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest);
5389 AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance); 5487 AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance);
5390 AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing); 5488 AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing);
@@ -5445,8 +5543,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5445 AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); 5543 AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false);
5446 AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); 5544 AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false);
5447 AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); 5545 AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false);
5448 AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage); 5546 AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false);
5449 AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest); 5547 AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false);
5450 AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); 5548 AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest);
5451 AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); 5549 AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer);
5452 AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); 5550 AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket);
@@ -5478,7 +5576,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5478 AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); 5576 AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel);
5479 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); 5577 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest);
5480 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); 5578 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false);
5481 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest); 5579 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest, false);
5482 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); 5580 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest);
5483 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); 5581 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false);
5484 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); 5582 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false);
@@ -5591,83 +5689,137 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5591 5689
5592 #region Packet Handlers 5690 #region Packet Handlers
5593 5691
5692 public int TotalAgentUpdates { get; set; }
5693
5594 #region Scene/Avatar 5694 #region Scene/Avatar
5595 5695
5596 private bool HandleAgentUpdate(IClientAPI sener, Packet packet) 5696 // Threshold for body rotation to be a significant agent update
5697 private const float QDELTA = 0.000001f;
5698 // Threshold for camera rotation to be a significant agent update
5699 private const float VDELTA = 0.01f;
5700
5701 /// <summary>
5702 /// This checks the update significance against the last update made.
5703 /// </summary>
5704 /// <remarks>Can only be called by one thread at a time</remarks>
5705 /// <returns></returns>
5706 /// <param name='x'></param>
5707 public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5597 { 5708 {
5598 if (OnAgentUpdate != null) 5709 return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x);
5599 { 5710 }
5600 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5601 5711
5602 #region Packet Session and User Check 5712 /// <summary>
5603 if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId) 5713 /// This checks the movement/state update significance against the last update made.
5604 { 5714 /// </summary>
5605 PacketPool.Instance.ReturnPacket(packet); 5715 /// <remarks>Can only be called by one thread at a time</remarks>
5606 return false; 5716 /// <returns></returns>
5607 } 5717 /// <param name='x'></param>
5608 #endregion 5718 private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5719 {
5720 float qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2);
5721 //qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2);
5722
5723 bool movementSignificant =
5724 (qdelta1 > QDELTA) // significant if body rotation above threshold
5725 // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack
5726 // || (qdelta2 > QDELTA * 10) // significant if head rotation above threshold
5727 || (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed
5728 || (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands
5729 || (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed
5730 || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed
5731 || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed
5732 ;
5733 //if (movementSignificant)
5734 //{
5735 //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}",
5736 // qdelta1, qdelta2);
5737 //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}",
5738 // x.ControlFlags, x.Flags, x.Far, x.State);
5739 //}
5740 return movementSignificant;
5741 }
5609 5742
5610 bool update = false; 5743 /// <summary>
5611 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; 5744 /// This checks the camera update significance against the last update made.
5612 5745 /// </summary>
5613 if (m_lastAgentUpdateArgs != null) 5746 /// <remarks>Can only be called by one thread at a time</remarks>
5614 { 5747 /// <returns></returns>
5615 // These should be ordered from most-likely to 5748 /// <param name='x'></param>
5616 // least likely to change. I've made an initial 5749 private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5617 // guess at that. 5750 {
5618 update = 5751 float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis);
5619 ( 5752 float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter);
5620 (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || 5753 float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis);
5621 (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || 5754 float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis);
5622 (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) ||
5623 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
5624 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
5625 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
5626 (x.ControlFlags != 0) ||
5627 (x.Far != m_lastAgentUpdateArgs.Far) ||
5628 (x.Flags != m_lastAgentUpdateArgs.Flags) ||
5629 (x.State != m_lastAgentUpdateArgs.State) ||
5630 (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) ||
5631 (x.SessionID != m_lastAgentUpdateArgs.SessionID) ||
5632 (x.AgentID != m_lastAgentUpdateArgs.AgentID)
5633 );
5634 }
5635 else
5636 {
5637 m_lastAgentUpdateArgs = new AgentUpdateArgs();
5638 update = true;
5639 }
5640 5755
5641 if (update) 5756 bool cameraSignificant =
5642 { 5757 (vdelta1 > VDELTA) ||
5643// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); 5758 (vdelta2 > VDELTA) ||
5759 (vdelta3 > VDELTA) ||
5760 (vdelta4 > VDELTA)
5761 ;
5644 5762
5645 m_lastAgentUpdateArgs.AgentID = x.AgentID; 5763 //if (cameraSignificant)
5646 m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; 5764 //{
5647 m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; 5765 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}",
5648 m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter; 5766 // x.CameraAtAxis, x.CameraCenter);
5649 m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; 5767 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}",
5650 m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; 5768 // x.CameraLeftAxis, x.CameraUpAxis);
5651 m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags; 5769 //}
5652 m_lastAgentUpdateArgs.Far = x.Far;
5653 m_lastAgentUpdateArgs.Flags = x.Flags;
5654 m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation;
5655 m_lastAgentUpdateArgs.SessionID = x.SessionID;
5656 m_lastAgentUpdateArgs.State = x.State;
5657 5770
5658 UpdateAgent handlerAgentUpdate = OnAgentUpdate; 5771 return cameraSignificant;
5659 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; 5772 }
5660 5773
5661 if (handlerPreAgentUpdate != null) 5774 private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
5662 OnPreAgentUpdate(this, m_lastAgentUpdateArgs); 5775 {
5776 // We got here, which means that something in agent update was significant
5663 5777
5664 if (handlerAgentUpdate != null) 5778 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5665 OnAgentUpdate(this, m_lastAgentUpdateArgs); 5779 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
5666 5780
5667 handlerAgentUpdate = null; 5781 if (x.AgentID != AgentId || x.SessionID != SessionId)
5668 handlerPreAgentUpdate = null; 5782 return false;
5669 } 5783
5670 } 5784 // Before we update the current m_thisAgentUpdateArgs, let's check this again
5785 // to see what exactly changed
5786 bool movement = CheckAgentMovementUpdateSignificance(x);
5787 bool camera = CheckAgentCameraUpdateSignificance(x);
5788
5789 m_thisAgentUpdateArgs.AgentID = x.AgentID;
5790 m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation;
5791 m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
5792 m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter;
5793 m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
5794 m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
5795 m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags;
5796 m_thisAgentUpdateArgs.Far = x.Far;
5797 m_thisAgentUpdateArgs.Flags = x.Flags;
5798 m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation;
5799 m_thisAgentUpdateArgs.SessionID = x.SessionID;
5800 m_thisAgentUpdateArgs.State = x.State;
5801
5802 UpdateAgent handlerAgentUpdate = OnAgentUpdate;
5803 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
5804 UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate;
5805
5806 // Was there a significant movement/state change?
5807 if (movement)
5808 {
5809 if (handlerPreAgentUpdate != null)
5810 OnPreAgentUpdate(this, m_thisAgentUpdateArgs);
5811
5812 if (handlerAgentUpdate != null)
5813 OnAgentUpdate(this, m_thisAgentUpdateArgs);
5814 }
5815 // Was there a significant camera(s) change?
5816 if (camera)
5817 if (handlerAgentCameraUpdate != null)
5818 handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs);
5819
5820 handlerAgentUpdate = null;
5821 handlerPreAgentUpdate = null;
5822 handlerAgentCameraUpdate = null;
5671 5823
5672 PacketPool.Instance.ReturnPacket(packet); 5824 PacketPool.Instance.ReturnPacket(packet);
5673 5825
@@ -6257,6 +6409,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6257 //m_log.Info("[LAND]: LAND:" + modify.ToString()); 6409 //m_log.Info("[LAND]: LAND:" + modify.ToString());
6258 if (modify.ParcelData.Length > 0) 6410 if (modify.ParcelData.Length > 0)
6259 { 6411 {
6412 // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore,
6413 // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit.
6414 m_justEditedTerrain = true; // Prevent terrain packet (Land layer) from being queued, make it unreliable
6260 if (OnModifyTerrain != null) 6415 if (OnModifyTerrain != null)
6261 { 6416 {
6262 for (int i = 0; i < modify.ParcelData.Length; i++) 6417 for (int i = 0; i < modify.ParcelData.Length; i++)
@@ -6272,6 +6427,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6272 } 6427 }
6273 } 6428 }
6274 } 6429 }
6430 m_justEditedTerrain = false; // Queue terrain packet (Land layer) if necessary, make it reliable again
6275 } 6431 }
6276 6432
6277 return true; 6433 return true;
@@ -6633,6 +6789,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6633 } 6789 }
6634 #endregion 6790 #endregion
6635 6791
6792 if (SceneAgent.IsChildAgent)
6793 {
6794 SendCantSitBecauseChildAgentResponse();
6795 return true;
6796 }
6797
6636 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; 6798 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit;
6637 6799
6638 if (handlerAgentRequestSit != null) 6800 if (handlerAgentRequestSit != null)
@@ -6657,6 +6819,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6657 } 6819 }
6658 #endregion 6820 #endregion
6659 6821
6822 if (SceneAgent.IsChildAgent)
6823 {
6824 SendCantSitBecauseChildAgentResponse();
6825 return true;
6826 }
6827
6660 AgentSit handlerAgentSit = OnAgentSit; 6828 AgentSit handlerAgentSit = OnAgentSit;
6661 if (handlerAgentSit != null) 6829 if (handlerAgentSit != null)
6662 { 6830 {
@@ -6666,6 +6834,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6666 return true; 6834 return true;
6667 } 6835 }
6668 6836
6837 /// <summary>
6838 /// Used when a child agent gets a sit response which should not be fulfilled.
6839 /// </summary>
6840 private void SendCantSitBecauseChildAgentResponse()
6841 {
6842 SendAlertMessage("Try moving closer. Can't sit on object because it is not in the same region as you.");
6843 }
6844
6669 private bool HandleSoundTrigger(IClientAPI sender, Packet Pack) 6845 private bool HandleSoundTrigger(IClientAPI sender, Packet Pack)
6670 { 6846 {
6671 SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack; 6847 SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack;
@@ -7876,129 +8052,145 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7876 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); 8052 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request");
7877 8053
7878 TransferRequestPacket transfer = (TransferRequestPacket)Pack; 8054 TransferRequestPacket transfer = (TransferRequestPacket)Pack;
7879 //m_log.Debug("Transfer Request: " + transfer.ToString());
7880 // Validate inventory transfers
7881 // Has to be done here, because AssetCache can't do it
7882 //
7883 UUID taskID = UUID.Zero; 8055 UUID taskID = UUID.Zero;
7884 if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) 8056 if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem)
7885 { 8057 {
7886 taskID = new UUID(transfer.TransferInfo.Params, 48);
7887 UUID itemID = new UUID(transfer.TransferInfo.Params, 64);
7888 UUID requestID = new UUID(transfer.TransferInfo.Params, 80);
7889
7890// m_log.DebugFormat(
7891// "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}",
7892// requestID, itemID, taskID, Name);
7893
7894 if (!(((Scene)m_scene).Permissions.BypassPermissions())) 8058 if (!(((Scene)m_scene).Permissions.BypassPermissions()))
7895 { 8059 {
7896 if (taskID != UUID.Zero) // Prim 8060 // We're spawning a thread because the permissions check can block this thread
8061 Util.FireAndForget(delegate
7897 { 8062 {
7898 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); 8063 // This requests the asset if needed
8064 HandleSimInventoryTransferRequestWithPermsCheck(sender, transfer);
8065 });
8066 return true;
8067 }
8068 }
8069 else if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate)
8070 {
8071 //TransferRequestPacket does not include covenant uuid?
8072 //get scene covenant uuid
8073 taskID = m_scene.RegionInfo.RegionSettings.Covenant;
8074 }
7899 8075
7900 if (part == null) 8076 // This is non-blocking
7901 { 8077 MakeAssetRequest(transfer, taskID);
7902 m_log.WarnFormat(
7903 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist",
7904 Name, requestID, itemID, taskID);
7905 return true;
7906 }
7907 8078
7908 TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); 8079 return true;
7909 if (tii == null) 8080 }
7910 {
7911 m_log.WarnFormat(
7912 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist",
7913 Name, requestID, itemID, taskID);
7914 return true;
7915 }
7916 8081
7917 if (tii.Type == (int)AssetType.LSLText) 8082 private void HandleSimInventoryTransferRequestWithPermsCheck(IClientAPI sender, TransferRequestPacket transfer)
7918 { 8083 {
7919 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) 8084 UUID taskID = new UUID(transfer.TransferInfo.Params, 48);
7920 return true; 8085 UUID itemID = new UUID(transfer.TransferInfo.Params, 64);
7921 } 8086 UUID requestID = new UUID(transfer.TransferInfo.Params, 80);
7922 else if (tii.Type == (int)AssetType.Notecard)
7923 {
7924 if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId))
7925 return true;
7926 }
7927 else
7928 {
7929 // TODO: Change this code to allow items other than notecards and scripts to be successfully
7930 // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule
7931 if (part.OwnerID != AgentId)
7932 {
7933 m_log.WarnFormat(
7934 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}",
7935 Name, requestID, itemID, taskID, part.OwnerID);
7936 return true;
7937 }
7938 8087
7939 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) 8088 //m_log.DebugFormat(
7940 { 8089 // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}",
7941 m_log.WarnFormat( 8090 // requestID, itemID, taskID, Name);
7942 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set",
7943 Name, requestID, itemID, taskID);
7944 return true;
7945 }
7946 8091
7947 if (tii.OwnerID != AgentId) 8092 //m_log.Debug("Transfer Request: " + transfer.ToString());
7948 { 8093 // Validate inventory transfers
7949 m_log.WarnFormat( 8094 // Has to be done here, because AssetCache can't do it
7950 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}", 8095 //
7951 Name, requestID, itemID, taskID, tii.OwnerID); 8096 if (taskID != UUID.Zero) // Prim
7952 return true; 8097 {
7953 } 8098 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID);
7954 8099
7955 if (( 8100 if (part == null)
7956 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) 8101 {
7957 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) 8102 m_log.WarnFormat(
7958 { 8103 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist",
7959 m_log.WarnFormat( 8104 Name, requestID, itemID, taskID);
7960 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", 8105 return;
7961 Name, requestID, itemID, taskID); 8106 }
7962 return true;
7963 }
7964 8107
7965 if (tii.AssetID != requestID) 8108 TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID);
7966 { 8109 if (tii == null)
7967 m_log.WarnFormat( 8110 {
7968 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", 8111 m_log.WarnFormat(
7969 Name, requestID, itemID, taskID, tii.AssetID); 8112 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist",
7970 return true; 8113 Name, requestID, itemID, taskID);
7971 } 8114 return;
7972 } 8115 }
8116
8117 if (tii.Type == (int)AssetType.LSLText)
8118 {
8119 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId))
8120 return;
8121 }
8122 else if (tii.Type == (int)AssetType.Notecard)
8123 {
8124 if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId))
8125 return;
8126 }
8127 else
8128 {
8129 // TODO: Change this code to allow items other than notecards and scripts to be successfully
8130 // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule
8131 if (part.OwnerID != AgentId)
8132 {
8133 m_log.WarnFormat(
8134 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}",
8135 Name, requestID, itemID, taskID, part.OwnerID);
8136 return;
7973 } 8137 }
7974 else // Agent 8138
8139 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0)
7975 { 8140 {
7976 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); 8141 m_log.WarnFormat(
7977 if (invAccess != null) 8142 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set",
7978 { 8143 Name, requestID, itemID, taskID);
7979 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID)) 8144 return;
7980 return false; 8145 }
7981 } 8146
7982 else 8147 if (tii.OwnerID != AgentId)
7983 { 8148 {
7984 return false; 8149 m_log.WarnFormat(
7985 } 8150 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}",
8151 Name, requestID, itemID, taskID, tii.OwnerID);
8152 return;
8153 }
8154
8155 if ((
8156 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8157 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8158 {
8159 m_log.WarnFormat(
8160 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer",
8161 Name, requestID, itemID, taskID);
8162 return;
8163 }
8164
8165 if (tii.AssetID != requestID)
8166 {
8167 m_log.WarnFormat(
8168 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}",
8169 Name, requestID, itemID, taskID, tii.AssetID);
8170 return;
7986 } 8171 }
7987 } 8172 }
7988 } 8173 }
7989 else 8174 else // Agent
7990 if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate) 8175 {
8176 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
8177 if (invAccess != null)
8178 {
8179 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID))
8180 return;
8181 }
8182 else
7991 { 8183 {
7992 //TransferRequestPacket does not include covenant uuid? 8184 return;
7993 //get scene covenant uuid
7994 taskID = m_scene.RegionInfo.RegionSettings.Covenant;
7995 } 8185 }
8186 }
7996 8187
8188 // Permissions out of the way, let's request the asset
7997 MakeAssetRequest(transfer, taskID); 8189 MakeAssetRequest(transfer, taskID);
7998 8190
7999 return true;
8000 } 8191 }
8001 8192
8193
8002 private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack) 8194 private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack)
8003 { 8195 {
8004 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; 8196 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack;
@@ -11729,8 +11921,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11729 } 11921 }
11730 11922
11731 /// <summary> 11923 /// <summary>
11732 /// Send a response back to a client when it asks the asset server (via the region server) if it has
11733 /// its appearance texture cached.
11734 /// </summary> 11924 /// </summary>
11735 /// <remarks> 11925 /// <remarks>
11736 /// At the moment, we always reply that there is no cached texture. 11926 /// At the moment, we always reply that there is no cached texture.
@@ -11738,6 +11928,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11738 /// <param name="simclient"></param> 11928 /// <param name="simclient"></param>
11739 /// <param name="packet"></param> 11929 /// <param name="packet"></param>
11740 /// <returns></returns> 11930 /// <returns></returns>
11931 // TODO: Convert old handler to use new method
11932 /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11933 {
11934 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11935
11936 if (cachedtex.AgentData.SessionID != SessionId)
11937 return false;
11938
11939
11940 List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>();
11941
11942 for (int i = 0; i < cachedtex.WearableData.Length; i++)
11943 {
11944 CachedTextureRequestArg arg = new CachedTextureRequestArg();
11945 arg.BakedTextureIndex = cachedtex.WearableData[i].TextureIndex;
11946 arg.WearableHashID = cachedtex.WearableData[i].ID;
11947
11948 requestArgs.Add(arg);
11949 }
11950
11951 CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest;
11952 if (handlerCachedTextureRequest != null)
11953 {
11954 handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs);
11955 }
11956
11957 return true;
11958 }*/
11959
11741 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) 11960 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11742 { 11961 {
11743 //m_log.Debug("texture cached: " + packet.ToString()); 11962 //m_log.Debug("texture cached: " + packet.ToString());
@@ -11896,6 +12115,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11896 return true; 12115 return true;
11897 } 12116 }
11898 12117
12118 /// <summary>
12119 /// Send a response back to a client when it asks the asset server (via the region server) if it has
12120 /// its appearance texture cached.
12121 /// </summary>
12122 /// <param name="avatar"></param>
12123 /// <param name="serial"></param>
12124 /// <param name="cachedTextures"></param>
12125 /// <returns></returns>
12126 public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures)
12127 {
12128 ScenePresence presence = avatar as ScenePresence;
12129 if (presence == null)
12130 return;
12131
12132 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
12133
12134 // TODO: don't create new blocks if recycling an old packet
12135 cachedresp.AgentData.AgentID = m_agentId;
12136 cachedresp.AgentData.SessionID = m_sessionId;
12137 cachedresp.AgentData.SerialNum = serial;
12138 cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cachedTextures.Count];
12139
12140 for (int i = 0; i < cachedTextures.Count; i++)
12141 {
12142 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12143 cachedresp.WearableData[i].TextureIndex = (byte)cachedTextures[i].BakedTextureIndex;
12144 cachedresp.WearableData[i].TextureID = cachedTextures[i].BakedTextureID;
12145 cachedresp.WearableData[i].HostName = new byte[0];
12146 }
12147
12148 cachedresp.Header.Zerocoded = true;
12149 OutPacket(cachedresp, ThrottleOutPacketType.Task);
12150 }
12151
11899 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) 12152 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet)
11900 { 12153 {
11901 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; 12154 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet;
@@ -11921,8 +12174,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11921 if (part == null) 12174 if (part == null)
11922 { 12175 {
11923 // It's a ghost! tell the client to delete it from view. 12176 // It's a ghost! tell the client to delete it from view.
11924 simClient.SendKillObject(Scene.RegionInfo.RegionHandle, 12177 simClient.SendKillObject(new List<uint> { localId });
11925 new List<uint> { localId });
11926 } 12178 }
11927 else 12179 else
11928 { 12180 {
@@ -12326,7 +12578,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12326 ClientInfo info = m_udpClient.GetClientInfo(); 12578 ClientInfo info = m_udpClient.GetClientInfo();
12327 12579
12328 info.proxyEP = null; 12580 info.proxyEP = null;
12329 info.agentcircuit = RequestClientInfo(); 12581 if (info.agentcircuit == null)
12582 info.agentcircuit = RequestClientInfo();
12330 12583
12331 return info; 12584 return info;
12332 } 12585 }
@@ -12709,11 +12962,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12709 OutPacket(dialog, ThrottleOutPacketType.Task); 12962 OutPacket(dialog, ThrottleOutPacketType.Task);
12710 } 12963 }
12711 12964
12712 public void StopFlying(ISceneEntity p) 12965 public void SendAgentTerseUpdate(ISceneEntity p)
12713 { 12966 {
12714 if (p is ScenePresence) 12967 if (p is ScenePresence)
12715 { 12968 {
12716 ScenePresence presence = p as ScenePresence;
12717 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities 12969 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities
12718 // There's no explicit message to send the client to tell it to stop flying.. it relies on the 12970 // There's no explicit message to send the client to tell it to stop flying.. it relies on the
12719 // velocity, collision plane and avatar height 12971 // velocity, collision plane and avatar height
@@ -12721,34 +12973,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12721 // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air 12973 // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air
12722 // when the avatar stands up 12974 // when the avatar stands up
12723 12975
12724 Vector3 pos = presence.AbsolutePosition;
12725
12726 if (presence.Appearance.AvatarHeight != 127.0f)
12727 pos += new Vector3(0f, 0f, (presence.Appearance.AvatarHeight/6f));
12728 else
12729 pos += new Vector3(0f, 0f, (1.56f/6f));
12730
12731 presence.AbsolutePosition = pos;
12732
12733 // attach a suitable collision plane regardless of the actual situation to force the LLClient to land.
12734 // Collision plane below the avatar's position a 6th of the avatar's height is suitable.
12735 // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a
12736 // certain amount.. because the LLClient wouldn't land in that situation anyway.
12737
12738 // why are we still testing for this really old height value default???
12739 if (presence.Appearance.AvatarHeight != 127.0f)
12740 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - presence.Appearance.AvatarHeight/6f);
12741 else
12742 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f/6f));
12743
12744
12745 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = 12976 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block =
12746 CreateImprovedTerseBlock(p, false); 12977 CreateImprovedTerseBlock(p, false);
12747 12978
12748 const float TIME_DILATION = 1.0f; 12979 const float TIME_DILATION = 1.0f;
12749 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); 12980 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
12750 12981
12751
12752 ImprovedTerseObjectUpdatePacket packet 12982 ImprovedTerseObjectUpdatePacket packet
12753 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( 12983 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
12754 PacketType.ImprovedTerseObjectUpdate); 12984 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..d52ad7e 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>
@@ -160,6 +163,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
160 private int m_maxRTO = 60000; 163 private int m_maxRTO = 60000;
161 public bool m_deliverPackets = true; 164 public bool m_deliverPackets = true;
162 165
166 private ClientInfo m_info = new ClientInfo();
167
163 /// <summary> 168 /// <summary>
164 /// Default constructor 169 /// Default constructor
165 /// </summary> 170 /// </summary>
@@ -241,20 +246,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
241 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists 246 // 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 247 // of pending and needed ACKs for every client every time some method wants information about
243 // this connection is a recipe for poor performance 248 // this connection is a recipe for poor performance
244 ClientInfo info = new ClientInfo(); 249
245 info.pendingAcks = new Dictionary<uint, uint>(); 250 m_info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
246 info.needAck = new Dictionary<uint, byte[]>(); 251 m_info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
247 252 m_info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
248 info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; 253 m_info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
249 info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; 254 m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
250 info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; 255 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
251 info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; 256 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
252 info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; 257 m_info.totalThrottle = (int)m_throttleCategory.DripRate;
253 info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; 258
254 info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; 259 return m_info;
255 info.totalThrottle = (int)m_throttleCategory.DripRate;
256
257 return info;
258 } 260 }
259 261
260 /// <summary> 262 /// <summary>
@@ -646,15 +648,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
646 /// <param name="categories">Throttle categories to fire the callback for</param> 648 /// <param name="categories">Throttle categories to fire the callback for</param>
647 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) 649 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
648 { 650 {
649 if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) 651// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
652 if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
650 { 653 {
654 m_isQueueEmptyRunning = true;
655
656 int start = Environment.TickCount & Int32.MaxValue;
657 const int MIN_CALLBACK_MS = 30;
658
659 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
660 if (m_nextOnQueueEmpty == 0)
661 m_nextOnQueueEmpty = 1;
662
651 // Use a value of 0 to signal that FireQueueEmpty is running 663 // Use a value of 0 to signal that FireQueueEmpty is running
652 m_nextOnQueueEmpty = 0; 664// m_nextOnQueueEmpty = 0;
653 // Asynchronously run the callback 665
654 Util.FireAndForget(FireQueueEmpty, categories); 666 m_categories = categories;
667
668 if (HasUpdates(m_categories))
669 {
670 // Asynchronously run the callback
671 Util.FireAndForget(FireQueueEmpty, categories);
672 }
673 else
674 {
675 m_isQueueEmptyRunning = false;
676 }
655 } 677 }
656 } 678 }
657 679
680 private bool m_isQueueEmptyRunning;
681 private ThrottleOutPacketTypeFlags m_categories = 0;
682
658 /// <summary> 683 /// <summary>
659 /// Fires the OnQueueEmpty callback and sets the minimum time that it 684 /// Fires the OnQueueEmpty callback and sets the minimum time that it
660 /// can be called again 685 /// can be called again
@@ -664,22 +689,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
664 /// signature</param> 689 /// signature</param>
665 private void FireQueueEmpty(object o) 690 private void FireQueueEmpty(object o)
666 { 691 {
667 const int MIN_CALLBACK_MS = 30; 692// int start = Environment.TickCount & Int32.MaxValue;
693// const int MIN_CALLBACK_MS = 30;
668 694
669 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; 695// if (m_udpServer.IsRunningOutbound)
670 QueueEmpty callback = OnQueueEmpty; 696// {
671 697 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
672 int start = Environment.TickCount & Int32.MaxValue; 698 QueueEmpty callback = OnQueueEmpty;
673 699
674 if (callback != null) 700 if (callback != null)
675 { 701 {
676 try { callback(categories); } 702// if (m_udpServer.IsRunningOutbound)
677 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } 703// {
678 } 704 try { callback(categories); }
705 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
706// }
707 }
708// }
709
710// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
711// if (m_nextOnQueueEmpty == 0)
712// m_nextOnQueueEmpty = 1;
713
714// }
679 715
680 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; 716 m_isQueueEmptyRunning = false;
681 if (m_nextOnQueueEmpty == 0)
682 m_nextOnQueueEmpty = 1;
683 } 717 }
684 internal void ForceThrottleSetting(int throttle, int setting) 718 internal void ForceThrottleSetting(int throttle, int setting)
685 { 719 {
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 4154ef2..ad3f715 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,60 @@ 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 "OutgoingUDPSendsCount",
138 "Number of UDP sends performed",
139 "",
140 "",
141 "clientstack",
142 scene.Name,
143 StatType.Pull,
144 MeasuresOfInterest.AverageChangeOverTime,
145 stat => stat.Value = m_udpServer.UdpSends,
146 StatVerbosity.Debug));
147
148 StatsManager.RegisterStat(
149 new Stat(
150 "AverageUDPProcessTime",
151 "Average number of milliseconds taken to process each incoming UDP packet in a sample.",
152 "This is for initial receive processing which is separate from the later client LL packet processing stage.",
153 "ms",
154 "clientstack",
155 scene.Name,
156 StatType.Pull,
157 MeasuresOfInterest.None,
158 stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond,
159// stat =>
160// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, 7),
161 StatVerbosity.Debug));
86 } 162 }
87 163
88 public bool HandlesRegion(Location x) 164 public bool HandlesRegion(Location x)
@@ -107,10 +183,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
107 /// </summary> 183 /// </summary>
108 public class LLUDPServer : OpenSimUDPBase 184 public class LLUDPServer : OpenSimUDPBase
109 { 185 {
186 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
187
110 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> 188 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary>
111 public const int MTU = 1400; 189 public const int MTU = 1400;
112 190
113 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 191 /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary>
192 public int ClientLogoutsDueToNoReceives { get; private set; }
193
194 /// <summary>
195 /// Default packet debug level given to new clients
196 /// </summary>
197 public int DefaultClientPacketDebugLevel { get; set; }
114 198
115 /// <summary>The measured resolution of Environment.TickCount</summary> 199 /// <summary>The measured resolution of Environment.TickCount</summary>
116 public readonly float TickCountResolution; 200 public readonly float TickCountResolution;
@@ -184,6 +268,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
184 protected bool m_sendPing; 268 protected bool m_sendPing;
185 269
186 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); 270 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
271
272 /// <summary>
273 /// Event used to signal when queued packets are available for sending.
274 /// </summary>
275 /// <remarks>
276 /// This allows the outbound loop to only operate when there is data to send rather than continuously polling.
277 /// Some data is sent immediately and not queued. That data would not trigger this event.
278 /// </remarks>
279 private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
280
187 private Pool<IncomingPacket> m_incomingPacketPool; 281 private Pool<IncomingPacket> m_incomingPacketPool;
188 282
189 /// <summary> 283 /// <summary>
@@ -204,7 +298,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
204 298
205 public Socket Server { get { return null; } } 299 public Socket Server { get { return null; } }
206 300
207 private int m_malformedCount = 0; // Guard against a spamming attack 301 /// <summary>
302 /// Record how many inbound packets could not be recognized as LLUDP packets.
303 /// </summary>
304 public int IncomingMalformedPacketCount { get; private set; }
305
306 /// <summary>
307 /// Record how many inbound packets could not be associated with a simulator circuit.
308 /// </summary>
309 public int IncomingOrphanedPacketCount { get; private set; }
208 310
209 /// <summary> 311 /// <summary>
210 /// Record current outgoing client for monitoring purposes. 312 /// Record current outgoing client for monitoring purposes.
@@ -461,6 +563,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
461 m_scene = (Scene)scene; 563 m_scene = (Scene)scene;
462 m_location = new Location(m_scene.RegionInfo.RegionHandle); 564 m_location = new Location(m_scene.RegionInfo.RegionHandle);
463 565
566 StatsManager.RegisterStat(
567 new Stat(
568 "InboxPacketsCount",
569 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
570 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
571 "",
572 "clientstack",
573 scene.Name,
574 StatType.Pull,
575 MeasuresOfInterest.AverageChangeOverTime,
576 stat => stat.Value = packetInbox.Count,
577 StatVerbosity.Debug));
578
464 // XXX: These stats are also pool stats but we register them separately since they are currently not 579 // 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() 580 // turned on and off by EnablePools()/DisablePools()
466 StatsManager.RegisterStat( 581 StatsManager.RegisterStat(
@@ -521,6 +636,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
521 EnablePoolStats(); 636 EnablePoolStats();
522 637
523 MainConsole.Instance.Commands.AddCommand( 638 MainConsole.Instance.Commands.AddCommand(
639 "Debug", false, "debug lludp packet",
640 "debug lludp packet [--default] <level> [<avatar-first-name> <avatar-last-name>]",
641 "Turn on packet debugging",
642 "If level > 255 then all incoming and outgoing packets are logged.\n"
643 + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n"
644 + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n"
645 + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n"
646 + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n"
647 + "If level <= 0 then no packets are logged.\n"
648 + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n"
649 + "In this case, you cannot also specify an avatar name.\n"
650 + "If an avatar name is given then only packets from that avatar are logged.",
651 HandlePacketCommand);
652
653 MainConsole.Instance.Commands.AddCommand(
524 "Debug", 654 "Debug",
525 false, 655 false,
526 "debug lludp start", 656 "debug lludp start",
@@ -559,10 +689,78 @@ namespace OpenSim.Region.ClientStack.LindenUDP
559 "debug lludp status", 689 "debug lludp status",
560 "Return status of LLUDP packet processing.", 690 "Return status of LLUDP packet processing.",
561 HandleStatusCommand); 691 HandleStatusCommand);
692
693 MainConsole.Instance.Commands.AddCommand(
694 "Debug",
695 false,
696 "debug lludp toggle agentupdate",
697 "debug lludp toggle agentupdate",
698 "Toggle whether agentupdate packets are processed or simply discarded.",
699 HandleAgentUpdateCommand);
700 }
701
702 private void HandlePacketCommand(string module, string[] args)
703 {
704 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
705 return;
706
707 bool setAsDefaultLevel = false;
708 OptionSet optionSet = new OptionSet().Add("default", o => setAsDefaultLevel = o != null);
709 List<string> filteredArgs = optionSet.Parse(args);
710
711 string name = null;
712
713 if (filteredArgs.Count == 6)
714 {
715 if (!setAsDefaultLevel)
716 {
717 name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]);
718 }
719 else
720 {
721 MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default logging level");
722 return;
723 }
724 }
725
726 if (filteredArgs.Count > 3)
727 {
728 int newDebug;
729 if (int.TryParse(filteredArgs[3], out newDebug))
730 {
731 if (setAsDefaultLevel)
732 {
733 DefaultClientPacketDebugLevel = newDebug;
734 MainConsole.Instance.OutputFormat(
735 "Debug packet debug for new clients set to {0} in {1}", DefaultClientPacketDebugLevel, m_scene.Name);
736 }
737 else
738 {
739 m_scene.ForEachScenePresence(sp =>
740 {
741 if (name == null || sp.Name == name)
742 {
743 MainConsole.Instance.OutputFormat(
744 "Packet debug for {0} ({1}) set to {2} in {3}",
745 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name);
746
747 sp.ControllingClient.DebugPacketLevel = newDebug;
748 }
749 });
750 }
751 }
752 else
753 {
754 MainConsole.Instance.Output("Usage: debug lludp packet [--default] 0..255 [<first-name> <last-name>]");
755 }
756 }
562 } 757 }
563 758
564 private void HandleStartCommand(string module, string[] args) 759 private void HandleStartCommand(string module, string[] args)
565 { 760 {
761 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
762 return;
763
566 if (args.Length != 4) 764 if (args.Length != 4)
567 { 765 {
568 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); 766 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
@@ -580,6 +778,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
580 778
581 private void HandleStopCommand(string module, string[] args) 779 private void HandleStopCommand(string module, string[] args)
582 { 780 {
781 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
782 return;
783
583 if (args.Length != 4) 784 if (args.Length != 4)
584 { 785 {
585 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); 786 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
@@ -597,6 +798,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
597 798
598 private void HandlePoolCommand(string module, string[] args) 799 private void HandlePoolCommand(string module, string[] args)
599 { 800 {
801 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
802 return;
803
600 if (args.Length != 4) 804 if (args.Length != 4)
601 { 805 {
602 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); 806 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
@@ -627,8 +831,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
627 } 831 }
628 } 832 }
629 833
834 bool m_discardAgentUpdates;
835
836 private void HandleAgentUpdateCommand(string module, string[] args)
837 {
838 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
839 return;
840
841 m_discardAgentUpdates = !m_discardAgentUpdates;
842
843 MainConsole.Instance.OutputFormat(
844 "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name);
845 }
846
630 private void HandleStatusCommand(string module, string[] args) 847 private void HandleStatusCommand(string module, string[] args)
631 { 848 {
849 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
850 return;
851
632 MainConsole.Instance.OutputFormat( 852 MainConsole.Instance.OutputFormat(
633 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); 853 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled");
634 854
@@ -636,6 +856,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
636 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); 856 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
637 857
638 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); 858 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off");
859
860 MainConsole.Instance.OutputFormat(
861 "Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel);
639 } 862 }
640 863
641 public bool HandlesRegion(Location x) 864 public bool HandlesRegion(Location x)
@@ -721,6 +944,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
721 } 944 }
722 945
723 PacketPool.Instance.ReturnPacket(packet); 946 PacketPool.Instance.ReturnPacket(packet);
947
948 m_dataPresentEvent.Set();
724 } 949 }
725 950
726 /// <summary> 951 /// <summary>
@@ -883,7 +1108,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 1108 // 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. 1109 // 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. 1110 // This is the same as processing as the async process of a logout request.
886 Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); 1111 Util.FireAndForget(o => DeactivateClientDueToTimeout(client, timeoutTicks));
887 1112
888 return; 1113 return;
889 } 1114 }
@@ -1002,6 +1227,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1002 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; 1227 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
1003 } 1228 }
1004 1229
1230 private void RecordMalformedInboundPacket(IPEndPoint endPoint)
1231 {
1232// if (m_malformedCount < 100)
1233// m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1234
1235 IncomingMalformedPacketCount++;
1236
1237 if ((IncomingMalformedPacketCount % 10000) == 0)
1238 m_log.WarnFormat(
1239 "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}",
1240 IncomingMalformedPacketCount, endPoint);
1241 }
1242
1005 public override void PacketReceived(UDPPacketBuffer buffer) 1243 public override void PacketReceived(UDPPacketBuffer buffer)
1006 { 1244 {
1007 // Debugging/Profiling 1245 // Debugging/Profiling
@@ -1023,6 +1261,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1023// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", 1261// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
1024// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 1262// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1025 1263
1264 RecordMalformedInboundPacket(endPoint);
1265
1026 return; // Drop undersized packet 1266 return; // Drop undersized packet
1027 } 1267 }
1028 1268
@@ -1041,6 +1281,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1041// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", 1281// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}",
1042// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 1282// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1043 1283
1284 RecordMalformedInboundPacket(endPoint);
1285
1044 return; // Malformed header 1286 return; // Malformed header
1045 } 1287 }
1046 1288
@@ -1056,34 +1298,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1056 // Only allocate a buffer for zerodecoding if the packet is zerocoded 1298 // Only allocate a buffer for zerodecoding if the packet is zerocoded
1057 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 1299 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
1058 } 1300 }
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) 1301 catch (Exception e)
1071 { 1302 {
1072 if (m_malformedCount < 100) 1303 if (IncomingMalformedPacketCount < 100)
1073 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); 1304 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 } 1305 }
1080 1306
1081 // Fail-safe check 1307 // Fail-safe check
1082 if (packet == null) 1308 if (packet == null)
1083 { 1309 {
1084 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:", 1310 if (IncomingMalformedPacketCount < 100)
1085 buffer.DataLength, buffer.RemoteEndPoint); 1311 {
1086 m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); 1312 m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:",
1313 buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
1314 }
1315
1316 RecordMalformedInboundPacket(endPoint);
1317
1087 return; 1318 return;
1088 } 1319 }
1089 1320
@@ -1127,12 +1358,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1127 queue.Enqueue(buffer); 1358 queue.Enqueue(buffer);
1128 return; 1359 return;
1129 } 1360 }
1361 else if (packet.Type == PacketType.CompleteAgentMovement)
1362 {
1363 // Send ack straight away to let the viewer know that we got it.
1364 SendAckImmediate(endPoint, packet.Header.Sequence);
1365
1366 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1367 // buffer.
1368 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1369
1370 Util.FireAndForget(HandleCompleteMovementIntoRegion, array);
1371
1372 return;
1373 }
1130 } 1374 }
1131 1375
1132 // Determine which agent this packet came from 1376 // Determine which agent this packet came from
1133 if (client == null || !(client is LLClientView)) 1377 if (client == null || !(client is LLClientView))
1134 { 1378 {
1135 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1379 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1380
1381 IncomingOrphanedPacketCount++;
1382
1383 if ((IncomingOrphanedPacketCount % 10000) == 0)
1384 m_log.WarnFormat(
1385 "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}",
1386 IncomingOrphanedPacketCount, endPoint);
1387
1136 return; 1388 return;
1137 } 1389 }
1138 1390
@@ -1233,6 +1485,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1233 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); 1485 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
1234 #endregion BinaryStats 1486 #endregion BinaryStats
1235 1487
1488 if (packet.Type == PacketType.AgentUpdate)
1489 {
1490 if (m_discardAgentUpdates)
1491 return;
1492
1493 ((LLClientView)client).TotalAgentUpdates++;
1494
1495 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
1496
1497 LLClientView llClient = client as LLClientView;
1498 if (agentUpdate.AgentData.SessionID != client.SessionId
1499 || agentUpdate.AgentData.AgentID != client.AgentId
1500 || !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) )
1501 {
1502 PacketPool.Instance.ReturnPacket(packet);
1503 return;
1504 }
1505 }
1506
1236 #region Ping Check Handling 1507 #region Ping Check Handling
1237 1508
1238 if (packet.Type == PacketType.StartPingCheck) 1509 if (packet.Type == PacketType.StartPingCheck)
@@ -1421,7 +1692,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1421 1692
1422 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1693 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1423 if (client != null) 1694 if (client != null)
1424 client.SceneAgent.SendInitialDataToMe(); 1695 {
1696 AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1697 bool tp = (aCircuit.teleportFlags > 0);
1698 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from
1699 if (!tp)
1700 client.SceneAgent.SendInitialDataToMe();
1701 }
1425 1702
1426 // Now we know we can handle more data 1703 // Now we know we can handle more data
1427 Thread.Sleep(200); 1704 Thread.Sleep(200);
@@ -1476,6 +1753,72 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1476 } 1753 }
1477 } 1754 }
1478 1755
1756 private void HandleCompleteMovementIntoRegion(object o)
1757 {
1758 IPEndPoint endPoint = null;
1759 IClientAPI client = null;
1760
1761 try
1762 {
1763 object[] array = (object[])o;
1764 endPoint = (IPEndPoint)array[0];
1765 CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1];
1766
1767 // Determine which agent this packet came from
1768 int count = 20;
1769 bool ready = false;
1770 while (!ready && count-- > 0)
1771 {
1772 if (m_scene.TryGetClient(endPoint, out client) && client.IsActive && client.SceneAgent != null)
1773 {
1774 LLClientView llClientView = (LLClientView)client;
1775 LLUDPClient udpClient = llClientView.UDPClient;
1776 if (udpClient != null && udpClient.IsConnected)
1777 ready = true;
1778 else
1779 {
1780 m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)");
1781 Thread.Sleep(200);
1782 }
1783 }
1784 else
1785 {
1786 m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)");
1787 Thread.Sleep(200);
1788 }
1789 }
1790
1791 if (client == null)
1792 return;
1793
1794 IncomingPacket incomingPacket1;
1795
1796 // Inbox insertion
1797 if (UsePools)
1798 {
1799 incomingPacket1 = m_incomingPacketPool.GetObject();
1800 incomingPacket1.Client = (LLClientView)client;
1801 incomingPacket1.Packet = packet;
1802 }
1803 else
1804 {
1805 incomingPacket1 = new IncomingPacket((LLClientView)client, packet);
1806 }
1807
1808 packetInbox.Enqueue(incomingPacket1);
1809 }
1810 catch (Exception e)
1811 {
1812 m_log.ErrorFormat(
1813 "[LLUDPSERVER]: CompleteMovementIntoRegion handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1814 endPoint != null ? endPoint.ToString() : "n/a",
1815 client != null ? client.Name : "unknown",
1816 client != null ? client.AgentId.ToString() : "unknown",
1817 e.Message,
1818 e.StackTrace);
1819 }
1820 }
1821
1479 /// <summary> 1822 /// <summary>
1480 /// Send an ack immediately to the given endpoint. 1823 /// Send an ack immediately to the given endpoint.
1481 /// </summary> 1824 /// </summary>
@@ -1544,6 +1887,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1544 1887
1545 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 1888 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1546 client.OnLogout += LogoutHandler; 1889 client.OnLogout += LogoutHandler;
1890 client.DebugPacketLevel = DefaultClientPacketDebugLevel;
1547 1891
1548 ((LLClientView)client).DisableFacelights = m_disableFacelights; 1892 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1549 1893
@@ -1562,21 +1906,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1562 /// regular client pings. 1906 /// regular client pings.
1563 /// </remarks> 1907 /// </remarks>
1564 /// <param name='client'></param> 1908 /// <param name='client'></param>
1565 private void DeactivateClientDueToTimeout(LLClientView client) 1909 /// <param name='timeoutTicks'></param>
1910 private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks)
1566 { 1911 {
1567 lock (client.CloseSyncLock) 1912 lock (client.CloseSyncLock)
1568 { 1913 {
1914 ClientLogoutsDueToNoReceives++;
1915
1569 m_log.WarnFormat( 1916 m_log.WarnFormat(
1570 "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", 1917 "[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); 1918 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, m_scene.Name);
1572
1573 StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
1574 1919
1575 if (!client.SceneAgent.IsChildAgent) 1920 if (!client.SceneAgent.IsChildAgent)
1576 client.Kick("Simulator logged you out due to connection timeout"); 1921 client.Kick("Simulator logged you out due to connection timeout.");
1577
1578 client.CloseWithoutChecks(true);
1579 } 1922 }
1923
1924 m_scene.IncomingCloseAgent(client.AgentId, true);
1580 } 1925 }
1581 1926
1582 private void IncomingPacketHandler() 1927 private void IncomingPacketHandler()
@@ -1592,6 +1937,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1592 { 1937 {
1593 IncomingPacket incomingPacket = null; 1938 IncomingPacket incomingPacket = null;
1594 1939
1940 /*
1595 // HACK: This is a test to try and rate limit packet handling on Mono. 1941 // 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 1942 // If it works, a more elegant solution can be devised
1597 if (Util.FireAndForgetCount() < 2) 1943 if (Util.FireAndForgetCount() < 2)
@@ -1599,6 +1945,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1599 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); 1945 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping");
1600 Thread.Sleep(30); 1946 Thread.Sleep(30);
1601 } 1947 }
1948 */
1602 1949
1603 if (packetInbox.Dequeue(100, ref incomingPacket)) 1950 if (packetInbox.Dequeue(100, ref incomingPacket))
1604 { 1951 {
@@ -1694,8 +2041,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1694 2041
1695 // If nothing was sent, sleep for the minimum amount of time before a 2042 // If nothing was sent, sleep for the minimum amount of time before a
1696 // token bucket could get more tokens 2043 // token bucket could get more tokens
2044 //if (!m_packetSent)
2045 // Thread.Sleep((int)TickCountResolution);
2046 //
2047 // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with
2048 // modern mono it reduces CPU base load since there is no more continuous polling.
1697 if (!m_packetSent) 2049 if (!m_packetSent)
1698 Thread.Sleep((int)TickCountResolution); 2050 m_dataPresentEvent.WaitOne(100);
1699 2051
1700 Watchdog.UpdateThread(); 2052 Watchdog.UpdateThread();
1701 } 2053 }
@@ -1912,7 +2264,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1912 if (!client.IsLoggingOut) 2264 if (!client.IsLoggingOut)
1913 { 2265 {
1914 client.IsLoggingOut = true; 2266 client.IsLoggingOut = true;
1915 client.Close(false, false); 2267 m_scene.IncomingCloseAgent(client.AgentId, false);
1916 } 2268 }
1917 } 2269 }
1918 } 2270 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index 7035e38..48c5b37 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
@@ -267,6 +301,8 @@ namespace OpenMetaverse
267 // to AsyncBeginReceive 301 // to AsyncBeginReceive
268 if (IsRunningInbound) 302 if (IsRunningInbound)
269 { 303 {
304 UdpReceives++;
305
270 // Asynchronous mode will start another receive before the 306 // Asynchronous mode will start another receive before the
271 // callback for this packet is even fired. Very parallel :-) 307 // callback for this packet is even fired. Very parallel :-)
272 if (m_asyncPacketHandling) 308 if (m_asyncPacketHandling)
@@ -278,6 +314,8 @@ namespace OpenMetaverse
278 314
279 try 315 try
280 { 316 {
317 int startTick = Util.EnvironmentTickCount();
318
281 // get the length of data actually read from the socket, store it with the 319 // get the length of data actually read from the socket, store it with the
282 // buffer 320 // buffer
283 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); 321 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
@@ -285,6 +323,23 @@ namespace OpenMetaverse
285 // call the abstract method PacketReceived(), passing the buffer that 323 // call the abstract method PacketReceived(), passing the buffer that
286 // has just been filled from the socket read. 324 // has just been filled from the socket read.
287 PacketReceived(buffer); 325 PacketReceived(buffer);
326
327 // If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler)
328 // then a particular stat may be inaccurate due to a race condition. We won't worry about this
329 // since this should be rare and won't cause a runtime problem.
330 if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
331 {
332 AverageReceiveTicksForLastSamplePeriod
333 = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
334
335 m_receiveTicksInCurrentSamplePeriod = 0;
336 m_currentReceiveTimeSamples = 0;
337 }
338 else
339 {
340 m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick);
341 m_currentReceiveTimeSamples++;
342 }
288 } 343 }
289 catch (SocketException) { } 344 catch (SocketException) { }
290 catch (ObjectDisposedException) { } 345 catch (ObjectDisposedException) { }
@@ -298,14 +353,13 @@ namespace OpenMetaverse
298 if (!m_asyncPacketHandling) 353 if (!m_asyncPacketHandling)
299 AsyncBeginReceive(); 354 AsyncBeginReceive();
300 } 355 }
301
302 } 356 }
303 } 357 }
304 358
305 public void AsyncBeginSend(UDPPacketBuffer buf) 359 public void AsyncBeginSend(UDPPacketBuffer buf)
306 { 360 {
307 if (IsRunningOutbound) 361// if (IsRunningOutbound)
308 { 362// {
309 try 363 try
310 { 364 {
311 m_udpSocket.BeginSendTo( 365 m_udpSocket.BeginSendTo(
@@ -319,7 +373,7 @@ namespace OpenMetaverse
319 } 373 }
320 catch (SocketException) { } 374 catch (SocketException) { }
321 catch (ObjectDisposedException) { } 375 catch (ObjectDisposedException) { }
322 } 376// }
323 } 377 }
324 378
325 void AsyncEndSend(IAsyncResult result) 379 void AsyncEndSend(IAsyncResult result)
@@ -328,6 +382,8 @@ namespace OpenMetaverse
328 { 382 {
329// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; 383// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
330 m_udpSocket.EndSendTo(result); 384 m_udpSocket.EndSendTo(result);
385
386 UdpSends++;
331 } 387 }
332 catch (SocketException) { } 388 catch (SocketException) { }
333 catch (ObjectDisposedException) { } 389 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/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();