aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack')
-rw-r--r--OpenSim/Region/ClientStack/IClientNetworkServer.cs15
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs136
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs27
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs618
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs36
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs8
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs6
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs20
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs4
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs1
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs26
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs166
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs115
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs4
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs926
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs7
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs110
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs647
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs111
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs25
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs6
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs16
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs9
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs6
27 files changed, 1899 insertions, 1152 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..bbadc55
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs
@@ -0,0 +1,136 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Specialized;
31using System.Drawing;
32using System.Drawing.Imaging;
33using System.Reflection;
34using System.IO;
35using System.Web;
36using log4net;
37using Nini.Config;
38using Mono.Addins;
39using OpenMetaverse;
40using OpenMetaverse.StructuredData;
41using OpenSim.Framework;
42using OpenSim.Framework.Servers;
43using OpenSim.Framework.Servers.HttpServer;
44using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Region.Framework.Scenes;
46using OpenSim.Services.Interfaces;
47using Caps = OpenSim.Framework.Capabilities.Caps;
48using OpenSim.Capabilities.Handlers;
49
50namespace OpenSim.Region.ClientStack.Linden
51{
52 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AvatarPickerSearchModule")]
53 public class AvatarPickerSearchModule : INonSharedRegionModule
54 {
55// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56
57 private Scene m_scene;
58 private IPeople m_People;
59 private bool m_Enabled = false;
60
61 private string m_URL;
62
63 #region ISharedRegionModule Members
64
65 public void Initialise(IConfigSource source)
66 {
67 IConfig config = source.Configs["ClientStack.LindenCaps"];
68 if (config == null)
69 return;
70
71 m_URL = config.GetString("Cap_AvatarPickerSearch", string.Empty);
72 // Cap doesn't exist
73 if (m_URL != string.Empty)
74 m_Enabled = true;
75 }
76
77 public void AddRegion(Scene s)
78 {
79 if (!m_Enabled)
80 return;
81
82 m_scene = s;
83 }
84
85 public void RemoveRegion(Scene s)
86 {
87 if (!m_Enabled)
88 return;
89
90 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
91 m_scene = null;
92 }
93
94 public void RegionLoaded(Scene s)
95 {
96 if (!m_Enabled)
97 return;
98
99 m_People = m_scene.RequestModuleInterface<IPeople>();
100 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
101 }
102
103 public void PostInitialise()
104 {
105 }
106
107 public void Close() { }
108
109 public string Name { get { return "AvatarPickerSearchModule"; } }
110
111 public Type ReplaceableInterface
112 {
113 get { return null; }
114 }
115
116 #endregion
117
118 public void RegisterCaps(UUID agentID, Caps caps)
119 {
120 UUID capID = UUID.Random();
121
122 if (m_URL == "localhost")
123 {
124// m_log.DebugFormat("[AVATAR PICKER SEARCH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
125 caps.RegisterHandler(
126 "AvatarPickerSearch",
127 new AvatarPickerSearchHandler("/CAPS/" + capID + "/", m_People, "AvatarPickerSearch", "Search for avatars by name"));
128 }
129 else
130 {
131 // m_log.DebugFormat("[AVATAR PICKER SEARCH]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName);
132 caps.RegisterHandler("AvatarPickerSearch", m_URL);
133 }
134 }
135 }
136} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 8241e07..613bc24 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -282,13 +282,19 @@ namespace OpenSim.Region.ClientStack.Linden
282 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); 282 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
283 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); 283 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
284 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); 284 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
285 IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData); 285
286 IRequestHandler getObjectPhysicsDataHandler
287 = new RestStreamHandler(
288 "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null);
286 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); 289 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
287 IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost); 290 IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost);
288 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler); 291 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler);
289 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected); 292 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected);
290 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler); 293 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler);
291 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation); 294
295 IRequestHandler UpdateAgentInformationHandler
296 = new RestStreamHandler(
297 "POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation, "UpdateAgentInformation", null);
292 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); 298 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler);
293 299
294 m_HostCapsObj.RegisterHandler( 300 m_HostCapsObj.RegisterHandler(
@@ -361,18 +367,7 @@ namespace OpenSim.Region.ClientStack.Linden
361 foreach (OSD c in capsRequested) 367 foreach (OSD c in capsRequested)
362 validCaps.Add(c.AsString()); 368 validCaps.Add(c.AsString());
363 369
364 Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true, validCaps); 370 string result = LLSDHelpers.SerialiseLLSDReply(m_HostCapsObj.GetCapsDetails(true, validCaps));
365
366 // Add the external too
367 foreach (KeyValuePair<string, string> kvp in m_HostCapsObj.ExternalCapsHandlers)
368 {
369 if (!validCaps.Contains(kvp.Key))
370 continue;
371
372 caps[kvp.Key] = kvp.Value;
373 }
374
375 string result = LLSDHelpers.SerialiseLLSDReply(caps);
376 371
377 //m_log.DebugFormat("[CAPS] CapsRequest {0}", result); 372 //m_log.DebugFormat("[CAPS] CapsRequest {0}", result);
378 373
@@ -748,6 +743,10 @@ namespace OpenSim.Region.ClientStack.Linden
748 inType = (sbyte)InventoryType.Sound; 743 inType = (sbyte)InventoryType.Sound;
749 assType = (sbyte)AssetType.Sound; 744 assType = (sbyte)AssetType.Sound;
750 } 745 }
746 else if (inventoryType == "snapshot")
747 {
748 inType = (sbyte)InventoryType.Snapshot;
749 }
751 else if (inventoryType == "animation") 750 else if (inventoryType == "animation")
752 { 751 {
753 inType = (sbyte)InventoryType.Animation; 752 inType = (sbyte)InventoryType.Animation;
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
index eb40eb1..ca6c3ca 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -65,12 +65,18 @@ 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>();
71 78
72 private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>(); 79 private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>();
73 private Dictionary<UUID, UUID> m_QueueUUIDAvatarMapping = new Dictionary<UUID, UUID>();
74 private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>(); 80 private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>();
75 81
76 #region INonSharedRegionModule methods 82 #region INonSharedRegionModule methods
@@ -84,7 +90,6 @@ namespace OpenSim.Region.ClientStack.Linden
84 scene.RegisterModuleInterface<IEventQueue>(this); 90 scene.RegisterModuleInterface<IEventQueue>(this);
85 91
86 scene.EventManager.OnClientClosed += ClientClosed; 92 scene.EventManager.OnClientClosed += ClientClosed;
87 scene.EventManager.OnMakeChildAgent += MakeChildAgent;
88 scene.EventManager.OnRegisterCaps += OnRegisterCaps; 93 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
89 94
90 MainConsole.Instance.Commands.AddCommand( 95 MainConsole.Instance.Commands.AddCommand(
@@ -113,7 +118,6 @@ namespace OpenSim.Region.ClientStack.Linden
113 return; 118 return;
114 119
115 scene.EventManager.OnClientClosed -= ClientClosed; 120 scene.EventManager.OnClientClosed -= ClientClosed;
116 scene.EventManager.OnMakeChildAgent -= MakeChildAgent;
117 scene.EventManager.OnRegisterCaps -= OnRegisterCaps; 121 scene.EventManager.OnRegisterCaps -= OnRegisterCaps;
118 122
119 scene.UnregisterModuleInterface<IEventQueue>(this); 123 scene.UnregisterModuleInterface<IEventQueue>(this);
@@ -172,29 +176,6 @@ namespace OpenSim.Region.ClientStack.Linden
172 } 176 }
173 177
174 /// <summary> 178 /// <summary>
175 /// Always returns a valid queue
176 /// </summary>
177 /// <param name="agentId"></param>
178 /// <returns></returns>
179 private Queue<OSD> TryGetQueue(UUID agentId)
180 {
181 lock (queues)
182 {
183 if (!queues.ContainsKey(agentId))
184 {
185 /*
186 m_log.DebugFormat(
187 "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}",
188 agentId, m_scene.RegionInfo.RegionName);
189 */
190 queues[agentId] = new Queue<OSD>();
191 }
192
193 return queues[agentId];
194 }
195 }
196
197 /// <summary>
198 /// May return a null queue 179 /// May return a null queue
199 /// </summary> 180 /// </summary>
200 /// <param name="agentId"></param> 181 /// <param name="agentId"></param>
@@ -221,8 +202,17 @@ namespace OpenSim.Region.ClientStack.Linden
221 { 202 {
222 Queue<OSD> queue = GetQueue(avatarID); 203 Queue<OSD> queue = GetQueue(avatarID);
223 if (queue != null) 204 if (queue != null)
205 {
224 lock (queue) 206 lock (queue)
225 queue.Enqueue(ev); 207 queue.Enqueue(ev);
208 }
209 else
210 {
211 OSDMap evMap = (OSDMap)ev;
212 m_log.WarnFormat(
213 "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} when placing message {1} in region {2}",
214 avatarID, evMap["message"], m_scene.Name);
215 }
226 } 216 }
227 catch (NullReferenceException e) 217 catch (NullReferenceException e)
228 { 218 {
@@ -237,77 +227,22 @@ namespace OpenSim.Region.ClientStack.Linden
237 227
238 private void ClientClosed(UUID agentID, Scene scene) 228 private void ClientClosed(UUID agentID, Scene scene)
239 { 229 {
240// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); 230 //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 231
248 lock (queues) 232 lock (queues)
249 {
250 queues.Remove(agentID); 233 queues.Remove(agentID);
251 }
252 234
253 List<UUID> removeitems = new List<UUID>();
254 lock (m_AvatarQueueUUIDMapping) 235 lock (m_AvatarQueueUUIDMapping)
255 { 236 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 237
270 string eqgPath = GenerateEqgCapPath(eventQueueGetUuid); 238 lock (m_ids)
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
279 UUID searchval = UUID.Zero;
280
281 removeitems.Clear();
282
283 lock (m_QueueUUIDAvatarMapping)
284 { 239 {
285 foreach (UUID ky in m_QueueUUIDAvatarMapping.Keys) 240 if (!m_ids.ContainsKey(agentID))
286 { 241 m_ids.Remove(agentID);
287 searchval = m_QueueUUIDAvatarMapping[ky];
288
289 if (searchval == agentID)
290 {
291 removeitems.Add(ky);
292 }
293 }
294
295 foreach (UUID ky in removeitems)
296 m_QueueUUIDAvatarMapping.Remove(ky);
297 } 242 }
298 }
299 243
300 private void MakeChildAgent(ScenePresence avatar) 244 // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
301 { 245
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 } 246 }
312 247
313 /// <summary> 248 /// <summary>
@@ -322,85 +257,109 @@ namespace OpenSim.Region.ClientStack.Linden
322 public void OnRegisterCaps(UUID agentID, Caps caps) 257 public void OnRegisterCaps(UUID agentID, Caps caps)
323 { 258 {
324 // Register an event queue for the client 259 // Register an event queue for the client
325 260 m_log.DebugFormat(
326 //m_log.DebugFormat( 261 "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}",
327 // "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", 262 agentID, caps, m_scene.RegionInfo.RegionName);
328 // agentID, caps, m_scene.RegionInfo.RegionName);
329
330 // Let's instantiate a Queue for this agent right now
331 TryGetQueue(agentID);
332 263
333 UUID eventQueueGetUUID; 264 UUID eventQueueGetUUID;
265 Queue<OSD> queue;
266 Random rnd = new Random(Environment.TickCount);
267 int nrnd = rnd.Next(30000000);
268 if (nrnd < 0)
269 nrnd = -nrnd;
334 270
335 lock (m_AvatarQueueUUIDMapping) 271 lock (queues)
336 { 272 {
337 // Reuse open queues. The client does! 273 if (queues.ContainsKey(agentID))
338 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) 274 queue = queues[agentID];
275 else
276 queue = null;
277
278 if (queue == null)
339 { 279 {
340 //m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); 280 queue = new Queue<OSD>();
341 eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; 281 queues[agentID] = queue;
282
283 // push markers to handle old responses still waiting
284 // this will cost at most viewer getting two forced noevents
285 // even being a new queue better be safe
286 queue.Enqueue(null);
287 queue.Enqueue(null); // one should be enough
288
289 lock (m_AvatarQueueUUIDMapping)
290 {
291 eventQueueGetUUID = UUID.Random();
292 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID))
293 {
294 // oops this should not happen ?
295 m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID without a queue");
296 eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
297 }
298 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
299 }
300 lock (m_ids)
301 {
302 if (!m_ids.ContainsKey(agentID))
303 m_ids.Add(agentID, nrnd);
304 else
305 m_ids[agentID] = nrnd;
306 }
342 } 307 }
343 else 308 else
344 { 309 {
345 eventQueueGetUUID = UUID.Random(); 310 // push markers to handle old responses still waiting
346 //m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); 311 // this will cost at most viewer getting two forced noevents
312 // even being a new queue better be safe
313 queue.Enqueue(null);
314 queue.Enqueue(null); // one should be enough
315
316 // reuse or not to reuse TODO FIX
317 lock (m_AvatarQueueUUIDMapping)
318 {
319 // Reuse open queues. The client does!
320 // Its reuse caps path not queues those are been reused already
321 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID))
322 {
323 m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!");
324 eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
325 }
326 else
327 {
328 eventQueueGetUUID = UUID.Random();
329 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
330 m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!");
331 }
332 }
333 lock (m_ids)
334 {
335 // change to negative numbers so they are changed at end of sending first marker
336 // old data on a queue may be sent on a response for a new caps
337 // but at least will be sent with coerent IDs
338 if (!m_ids.ContainsKey(agentID))
339 m_ids.Add(agentID, -nrnd); // should not happen
340 else
341 m_ids[agentID] = -m_ids[agentID];
342 }
347 } 343 }
348 } 344 }
349 345
350 lock (m_QueueUUIDAvatarMapping) 346 caps.RegisterPollHandler(
351 { 347 "EventQueueGet",
352 if (!m_QueueUUIDAvatarMapping.ContainsKey(eventQueueGetUUID)) 348 new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS));
353 m_QueueUUIDAvatarMapping.Add(eventQueueGetUUID, agentID);
354 }
355
356 lock (m_AvatarQueueUUIDMapping)
357 {
358 if (!m_AvatarQueueUUIDMapping.ContainsKey(agentID))
359 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
360 }
361
362 string eventQueueGetPath = GenerateEqgCapPath(eventQueueGetUUID);
363
364 // Register this as a caps handler
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
385 Random rnd = new Random(Environment.TickCount);
386 lock (m_ids)
387 {
388 if (!m_ids.ContainsKey(agentID))
389 m_ids.Add(agentID, rnd.Next(30000000));
390 }
391 } 349 }
392 350
393 public bool HasEvents(UUID requestID, UUID agentID) 351 public bool HasEvents(UUID requestID, UUID agentID)
394 { 352 {
395 // Don't use this, because of race conditions at agent closing time
396 //Queue<OSD> queue = TryGetQueue(agentID);
397
398 Queue<OSD> queue = GetQueue(agentID); 353 Queue<OSD> queue = GetQueue(agentID);
399 if (queue != null) 354 if (queue != null)
400 lock (queue) 355 lock (queue)
356 {
357 //m_log.WarnFormat("POLLED FOR EVENTS BY {0} in {1} -- {2}", agentID, m_scene.RegionInfo.RegionName, queue.Count);
401 return queue.Count > 0; 358 return queue.Count > 0;
359 }
402 360
403 return false; 361 //m_log.WarnFormat("POLLED FOR EVENTS BY {0} unknown agent", agentID);
362 return true;
404 } 363 }
405 364
406 /// <summary> 365 /// <summary>
@@ -414,65 +373,80 @@ namespace OpenSim.Region.ClientStack.Linden
414 OSDMap ev = (OSDMap)element; 373 OSDMap ev = (OSDMap)element;
415 m_log.DebugFormat( 374 m_log.DebugFormat(
416 "Eq OUT {0,-30} to {1,-20} {2,-20}", 375 "Eq OUT {0,-30} to {1,-20} {2,-20}",
417 ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.RegionInfo.RegionName); 376 ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.Name);
418 } 377 }
419 } 378 }
420 379
421 public Hashtable GetEvents(UUID requestID, UUID pAgentId) 380 public Hashtable GetEvents(UUID requestID, UUID pAgentId)
422 { 381 {
423 if (DebugLevel >= 2) 382 if (DebugLevel >= 2)
424 m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); 383 m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.Name);
425 384
426 Queue<OSD> queue = TryGetQueue(pAgentId); 385 Queue<OSD> queue = GetQueue(pAgentId);
427 OSD element; 386 if (queue == null)
428 lock (queue)
429 { 387 {
430 if (queue.Count == 0) 388 return NoEvents(requestID, pAgentId);
431 return NoEvents(requestID, pAgentId);
432 element = queue.Dequeue(); // 15s timeout
433 } 389 }
434 390
391 OSD element = null;;
392 OSDArray array = new OSDArray();
435 int thisID = 0; 393 int thisID = 0;
436 lock (m_ids) 394 bool negativeID = false;
437 thisID = m_ids[pAgentId];
438 395
439 OSDArray array = new OSDArray(); 396 lock (queue)
440 if (element == null) // didn't have an event in 15s
441 {
442 // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say!
443 array.Add(EventQueueHelper.KeepAliveEvent());
444 //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName);
445 }
446 else
447 { 397 {
448 if (DebugLevel > 0) 398 if (queue.Count == 0)
449 LogOutboundDebugMessage(element, pAgentId); 399 return NoEvents(requestID, pAgentId);
450 400
451 array.Add(element); 401 lock (m_ids)
402 thisID = m_ids[pAgentId];
452 403
453 lock (queue) 404 if (thisID < 0)
454 { 405 {
455 while (queue.Count > 0) 406 negativeID = true;
456 { 407 thisID = -thisID;
457 element = queue.Dequeue(); 408 }
409
410 while (queue.Count > 0)
411 {
412 element = queue.Dequeue();
413 // add elements until a marker is found
414 // so they get into a response
415 if (element == null)
416 break;
417 if (DebugLevel > 0)
418 LogOutboundDebugMessage(element, pAgentId);
419 array.Add(element);
420 thisID++;
421 }
422 }
458 423
459 if (DebugLevel > 0) 424 OSDMap events = null;
460 LogOutboundDebugMessage(element, pAgentId);
461 425
462 array.Add(element); 426 if (array.Count > 0)
463 thisID++; 427 {
464 } 428 events = new OSDMap();
465 } 429 events.Add("events", array);
430 events.Add("id", new OSDInteger(thisID));
466 } 431 }
467 432
468 OSDMap events = new OSDMap(); 433 if (negativeID && element == null)
469 events.Add("events", array); 434 {
435 Random rnd = new Random(Environment.TickCount);
436 thisID = rnd.Next(30000000);
437 if (thisID < 0)
438 thisID = -thisID;
439 }
470 440
471 events.Add("id", new OSDInteger(thisID));
472 lock (m_ids) 441 lock (m_ids)
473 { 442 {
474 m_ids[pAgentId] = thisID + 1; 443 m_ids[pAgentId] = thisID + 1;
475 } 444 }
445
446 // if there where no elements before a marker send a NoEvents
447 if (array.Count == 0)
448 return NoEvents(requestID, pAgentId);
449
476 Hashtable responsedata = new Hashtable(); 450 Hashtable responsedata = new Hashtable();
477 responsedata["int_response_code"] = 200; 451 responsedata["int_response_code"] = 200;
478 responsedata["content_type"] = "application/xml"; 452 responsedata["content_type"] = "application/xml";
@@ -495,289 +469,53 @@ namespace OpenSim.Region.ClientStack.Linden
495 responsedata["http_protocol_version"] = "HTTP/1.0"; 469 responsedata["http_protocol_version"] = "HTTP/1.0";
496 return responsedata; 470 return responsedata;
497 } 471 }
498 472
499// public Hashtable ProcessQueue(Hashtable request, UUID agentID, Caps caps)
500// {
501// // TODO: this has to be redone to not busy-wait (and block the thread),
502// // TODO: as soon as we have a non-blocking way to handle HTTP-requests.
503//
504//// if (m_log.IsDebugEnabled)
505//// {
506//// String debug = "[EVENTQUEUE]: Got request for agent {0} in region {1} from thread {2}: [ ";
507//// foreach (object key in request.Keys)
508//// {
509//// debug += key.ToString() + "=" + request[key].ToString() + " ";
510//// }
511//// m_log.DebugFormat(debug + " ]", agentID, m_scene.RegionInfo.RegionName, System.Threading.Thread.CurrentThread.Name);
512//// }
513//
514// Queue<OSD> queue = TryGetQueue(agentID);
515// OSD element;
516//
517// lock (queue)
518// element = queue.Dequeue(); // 15s timeout
519//
520// Hashtable responsedata = new Hashtable();
521//
522// int thisID = 0;
523// lock (m_ids)
524// thisID = m_ids[agentID];
525//
526// if (element == null)
527// {
528// //m_log.ErrorFormat("[EVENTQUEUE]: Nothing to process in " + m_scene.RegionInfo.RegionName);
529// if (thisID == -1) // close-request
530// {
531// m_log.ErrorFormat("[EVENTQUEUE]: 404 in " + m_scene.RegionInfo.RegionName);
532// responsedata["int_response_code"] = 404; //501; //410; //404;
533// responsedata["content_type"] = "text/plain";
534// responsedata["keepalive"] = false;
535// responsedata["str_response_string"] = "Closed EQG";
536// return responsedata;
537// }
538// responsedata["int_response_code"] = 502;
539// responsedata["content_type"] = "text/plain";
540// responsedata["keepalive"] = false;
541// responsedata["str_response_string"] = "Upstream error: ";
542// responsedata["error_status_text"] = "Upstream error:";
543// responsedata["http_protocol_version"] = "HTTP/1.0";
544// return responsedata;
545// }
546//
547// OSDArray array = new OSDArray();
548// if (element == null) // didn't have an event in 15s
549// {
550// // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say!
551// array.Add(EventQueueHelper.KeepAliveEvent());
552// //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
553// }
554// else
555// {
556// array.Add(element);
557//
558// if (element is OSDMap)
559// {
560// OSDMap ev = (OSDMap)element;
561// m_log.DebugFormat(
562// "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}",
563// ev["message"], m_scene.GetScenePresence(agentID).Name);
564// }
565//
566// lock (queue)
567// {
568// while (queue.Count > 0)
569// {
570// element = queue.Dequeue();
571//
572// if (element is OSDMap)
573// {
574// OSDMap ev = (OSDMap)element;
575// m_log.DebugFormat(
576// "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}",
577// ev["message"], m_scene.GetScenePresence(agentID).Name);
578// }
579//
580// array.Add(element);
581// thisID++;
582// }
583// }
584// }
585//
586// OSDMap events = new OSDMap();
587// events.Add("events", array);
588//
589// events.Add("id", new OSDInteger(thisID));
590// lock (m_ids)
591// {
592// m_ids[agentID] = thisID + 1;
593// }
594//
595// responsedata["int_response_code"] = 200;
596// responsedata["content_type"] = "application/xml";
597// responsedata["keepalive"] = false;
598// responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events);
599//
600// m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", agentID, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]);
601//
602// return responsedata;
603// }
604
605// public Hashtable EventQueuePath2(Hashtable request)
606// {
607// string capuuid = (string)request["uri"]; //path.Replace("/CAPS/EQG/","");
608// // pull off the last "/" in the path.
609// Hashtable responsedata = new Hashtable();
610// capuuid = capuuid.Substring(0, capuuid.Length - 1);
611// capuuid = capuuid.Replace("/CAPS/EQG/", "");
612// UUID AvatarID = UUID.Zero;
613// UUID capUUID = UUID.Zero;
614//
615// // parse the path and search for the avatar with it registered
616// if (UUID.TryParse(capuuid, out capUUID))
617// {
618// lock (m_QueueUUIDAvatarMapping)
619// {
620// if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID))
621// {
622// AvatarID = m_QueueUUIDAvatarMapping[capUUID];
623// }
624// }
625//
626// if (AvatarID != UUID.Zero)
627// {
628// return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsForUser(AvatarID));
629// }
630// else
631// {
632// responsedata["int_response_code"] = 404;
633// responsedata["content_type"] = "text/plain";
634// responsedata["keepalive"] = false;
635// responsedata["str_response_string"] = "Not Found";
636// responsedata["error_status_text"] = "Not Found";
637// responsedata["http_protocol_version"] = "HTTP/1.0";
638// return responsedata;
639// // return 404
640// }
641// }
642// else
643// {
644// responsedata["int_response_code"] = 404;
645// responsedata["content_type"] = "text/plain";
646// responsedata["keepalive"] = false;
647// responsedata["str_response_string"] = "Not Found";
648// responsedata["error_status_text"] = "Not Found";
649// responsedata["http_protocol_version"] = "HTTP/1.0";
650// return responsedata;
651// // return 404
652// }
653// }
654
655 public OSD EventQueueFallBack(string path, OSD request, string endpoint)
656 {
657 // This is a fallback element to keep the client from loosing EventQueueGet
658 // Why does CAPS fail sometimes!?
659 m_log.Warn("[EVENTQUEUE]: In the Fallback handler! We lost the Queue in the rest handler!");
660 string capuuid = path.Replace("/CAPS/EQG/","");
661 capuuid = capuuid.Substring(0, capuuid.Length - 1);
662
663// UUID AvatarID = UUID.Zero;
664 UUID capUUID = UUID.Zero;
665 if (UUID.TryParse(capuuid, out capUUID))
666 {
667/* Don't remove this yet code cleaners!
668 * Still testing this!
669 *
670 lock (m_QueueUUIDAvatarMapping)
671 {
672 if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID))
673 {
674 AvatarID = m_QueueUUIDAvatarMapping[capUUID];
675 }
676 }
677
678
679 if (AvatarID != UUID.Zero)
680 {
681 // Repair the CAP!
682 //OpenSim.Framework.Capabilities.Caps caps = m_scene.GetCapsHandlerForUser(AvatarID);
683 //string capsBase = "/CAPS/EQG/";
684 //caps.RegisterHandler("EventQueueGet",
685 //new RestHTTPHandler("POST", capsBase + capUUID.ToString() + "/",
686 //delegate(Hashtable m_dhttpMethod)
687 //{
688 // return ProcessQueue(m_dhttpMethod, AvatarID, caps);
689 //}));
690 // start new ID sequence.
691 Random rnd = new Random(System.Environment.TickCount);
692 lock (m_ids)
693 {
694 if (!m_ids.ContainsKey(AvatarID))
695 m_ids.Add(AvatarID, rnd.Next(30000000));
696 }
697
698
699 int thisID = 0;
700 lock (m_ids)
701 thisID = m_ids[AvatarID];
702
703 BlockingLLSDQueue queue = GetQueue(AvatarID);
704 OSDArray array = new OSDArray();
705 LLSD element = queue.Dequeue(15000); // 15s timeout
706 if (element == null)
707 {
708
709 array.Add(EventQueueHelper.KeepAliveEvent());
710 }
711 else
712 {
713 array.Add(element);
714 while (queue.Count() > 0)
715 {
716 array.Add(queue.Dequeue(1));
717 thisID++;
718 }
719 }
720 OSDMap events = new OSDMap();
721 events.Add("events", array);
722
723 events.Add("id", new LLSDInteger(thisID));
724
725 lock (m_ids)
726 {
727 m_ids[AvatarID] = thisID + 1;
728 }
729
730 return events;
731 }
732 else
733 {
734 return new LLSD();
735 }
736*
737*/
738 }
739 else
740 {
741 //return new LLSD();
742 }
743
744 return new OSDString("shutdown404!");
745 }
746
747 public void DisableSimulator(ulong handle, UUID avatarID) 473 public void DisableSimulator(ulong handle, UUID avatarID)
748 { 474 {
749 OSD item = EventQueueHelper.DisableSimulator(handle); 475 OSD item = EventQueueHelper.DisableSimulator(handle);
750 Enqueue(item, avatarID); 476 Enqueue(item, avatarID);
751 } 477 }
752 478
753 public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID) 479 public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY)
754 { 480 {
755 OSD item = EventQueueHelper.EnableSimulator(handle, endPoint); 481 m_log.DebugFormat("{0} EnableSimulator. handle={1}, avatarID={2}, regionSize={3},{4}>",
482 "[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY);
483
484 OSD item = EventQueueHelper.EnableSimulator(handle, endPoint, regionSizeX, regionSizeY);
756 Enqueue(item, avatarID); 485 Enqueue(item, avatarID);
757 } 486 }
758 487
759 public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath) 488 public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath,
489 ulong regionHandle, int regionSizeX, int regionSizeY)
760 { 490 {
761 OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath); 491 m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, avatarID={2}, regionSize={3},{4}>",
492 "[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY);
493 OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath, regionHandle, regionSizeX, regionSizeY);
762 Enqueue(item, avatarID); 494 Enqueue(item, avatarID);
763 } 495 }
764 496
765 public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, 497 public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess,
766 IPEndPoint regionExternalEndPoint, 498 IPEndPoint regionExternalEndPoint,
767 uint locationID, uint flags, string capsURL, 499 uint locationID, uint flags, string capsURL,
768 UUID avatarID) 500 UUID avatarID, int regionSizeX, int regionSizeY)
769 { 501 {
502 m_log.DebugFormat("{0} TeleportFinishEvent. handle={1}, avatarID={2}, regionSize={3},{4}>",
503 "[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY);
504
770 OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint, 505 OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint,
771 locationID, flags, capsURL, avatarID); 506 locationID, flags, capsURL, avatarID, regionSizeX, regionSizeY);
772 Enqueue(item, avatarID); 507 Enqueue(item, avatarID);
773 } 508 }
774 509
775 public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, 510 public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
776 IPEndPoint newRegionExternalEndPoint, 511 IPEndPoint newRegionExternalEndPoint,
777 string capsURL, UUID avatarID, UUID sessionID) 512 string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY)
778 { 513 {
514 m_log.DebugFormat("{0} CrossRegion. handle={1}, avatarID={2}, regionSize={3},{4}>",
515 "[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY);
516
779 OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint, 517 OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint,
780 capsURL, avatarID, sessionID); 518 capsURL, avatarID, sessionID, regionSizeX, regionSizeY);
781 Enqueue(item, avatarID); 519 Enqueue(item, avatarID);
782 } 520 }
783 521
@@ -794,12 +532,12 @@ namespace OpenSim.Region.ClientStack.Linden
794 532
795 } 533 }
796 534
797 public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, 535 public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat,
798 bool isModerator, bool textMute) 536 bool isModerator, bool textMute)
799 { 537 {
800 OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, 538 OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat,
801 isModerator, textMute); 539 isModerator, textMute);
802 Enqueue(item, toAgent); 540 Enqueue(item, fromAgent);
803 //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); 541 //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item);
804 } 542 }
805 543
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
index 7dcf137..3fb7de2 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
@@ -70,13 +70,15 @@ namespace OpenSim.Region.ClientStack.Linden
70 return llsdEvent; 70 return llsdEvent;
71 } 71 }
72 72
73 public static OSD EnableSimulator(ulong handle, IPEndPoint endPoint) 73 public static OSD EnableSimulator(ulong handle, IPEndPoint endPoint, int regionSizeX, int regionSizeY)
74 { 74 {
75 OSDMap llsdSimInfo = new OSDMap(3); 75 OSDMap llsdSimInfo = new OSDMap(5);
76 76
77 llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle))); 77 llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle)));
78 llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes())); 78 llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes()));
79 llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port)); 79 llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port));
80 llsdSimInfo.Add("RegionSizeX", new OSDInteger(regionSizeX));
81 llsdSimInfo.Add("RegionSizeY", new OSDInteger(regionSizeY));
80 82
81 OSDArray arr = new OSDArray(1); 83 OSDArray arr = new OSDArray(1);
82 arr.Add(llsdSimInfo); 84 arr.Add(llsdSimInfo);
@@ -104,7 +106,8 @@ namespace OpenSim.Region.ClientStack.Linden
104 106
105 public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, 107 public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
106 IPEndPoint newRegionExternalEndPoint, 108 IPEndPoint newRegionExternalEndPoint,
107 string capsURL, UUID agentID, UUID sessionID) 109 string capsURL, UUID agentID, UUID sessionID,
110 int regionSizeX, int regionSizeY)
108 { 111 {
109 OSDArray lookAtArr = new OSDArray(3); 112 OSDArray lookAtArr = new OSDArray(3);
110 lookAtArr.Add(OSD.FromReal(lookAt.X)); 113 lookAtArr.Add(OSD.FromReal(lookAt.X));
@@ -130,11 +133,13 @@ namespace OpenSim.Region.ClientStack.Linden
130 OSDArray agentDataArr = new OSDArray(1); 133 OSDArray agentDataArr = new OSDArray(1);
131 agentDataArr.Add(agentDataMap); 134 agentDataArr.Add(agentDataMap);
132 135
133 OSDMap regionDataMap = new OSDMap(4); 136 OSDMap regionDataMap = new OSDMap(6);
134 regionDataMap.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(handle))); 137 regionDataMap.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(handle)));
135 regionDataMap.Add("SeedCapability", OSD.FromString(capsURL)); 138 regionDataMap.Add("SeedCapability", OSD.FromString(capsURL));
136 regionDataMap.Add("SimIP", OSD.FromBinary(newRegionExternalEndPoint.Address.GetAddressBytes())); 139 regionDataMap.Add("SimIP", OSD.FromBinary(newRegionExternalEndPoint.Address.GetAddressBytes()));
137 regionDataMap.Add("SimPort", OSD.FromInteger(newRegionExternalEndPoint.Port)); 140 regionDataMap.Add("SimPort", OSD.FromInteger(newRegionExternalEndPoint.Port));
141 regionDataMap.Add("RegionSizeX", new OSDInteger(regionSizeX));
142 regionDataMap.Add("RegionSizeY", new OSDInteger(regionSizeY));
138 143
139 OSDArray regionDataArr = new OSDArray(1); 144 OSDArray regionDataArr = new OSDArray(1);
140 regionDataArr.Add(regionDataMap); 145 regionDataArr.Add(regionDataMap);
@@ -148,8 +153,9 @@ namespace OpenSim.Region.ClientStack.Linden
148 } 153 }
149 154
150 public static OSD TeleportFinishEvent( 155 public static OSD TeleportFinishEvent(
151 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, 156 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
152 uint locationID, uint flags, string capsURL, UUID agentID) 157 uint locationID, uint flags, string capsURL, UUID agentID,
158 int regionSizeX, int regionSizeY)
153 { 159 {
154 // not sure why flags get overwritten here 160 // not sure why flags get overwritten here
155 if ((flags & (uint)TeleportFlags.IsFlying) != 0) 161 if ((flags & (uint)TeleportFlags.IsFlying) != 0)
@@ -167,6 +173,8 @@ namespace OpenSim.Region.ClientStack.Linden
167 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port)); 173 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port));
168// info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation 174// info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation
169 info.Add("TeleportFlags", OSD.FromUInteger(flags)); 175 info.Add("TeleportFlags", OSD.FromUInteger(flags));
176 info.Add("RegionSizeX", new OSDInteger(regionSizeX));
177 info.Add("RegionSizeY", new OSDInteger(regionSizeY));
170 178
171 OSDArray infoArr = new OSDArray(); 179 OSDArray infoArr = new OSDArray();
172 infoArr.Add(info); 180 infoArr.Add(info);
@@ -194,12 +202,18 @@ namespace OpenSim.Region.ClientStack.Linden
194 return BuildEvent("ScriptRunningReply", body); 202 return BuildEvent("ScriptRunningReply", body);
195 } 203 }
196 204
197 public static OSD EstablishAgentCommunication(UUID agentID, string simIpAndPort, string seedcap) 205 public static OSD EstablishAgentCommunication(UUID agentID, string simIpAndPort, string seedcap,
206 ulong regionHandle, int regionSizeX, int regionSizeY)
198 { 207 {
199 OSDMap body = new OSDMap(3); 208 OSDMap body = new OSDMap(6)
200 body.Add("agent-id", new OSDUUID(agentID)); 209 {
201 body.Add("sim-ip-and-port", new OSDString(simIpAndPort)); 210 {"agent-id", new OSDUUID(agentID)},
202 body.Add("seed-capability", new OSDString(seedcap)); 211 {"sim-ip-and-port", new OSDString(simIpAndPort)},
212 {"seed-capability", new OSDString(seedcap)},
213 {"region-handle", OSD.FromULong(regionHandle)},
214 {"region-size-x", OSD.FromInteger(regionSizeX)},
215 {"region-size-y", OSD.FromInteger(regionSizeY)}
216 };
203 217
204 return BuildEvent("EstablishAgentCommunication", body); 218 return BuildEvent("EstablishAgentCommunication", body);
205 } 219 }
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
index 141af8a..9e24bce 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
@@ -76,7 +76,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
76 } 76 }
77 77
78 [Test] 78 [Test]
79 public void AddForClient() 79 public void TestAddForClient()
80 { 80 {
81 TestHelpers.InMethod(); 81 TestHelpers.InMethod();
82// log4net.Config.XmlConfigurator.Configure(); 82// log4net.Config.XmlConfigurator.Configure();
@@ -88,15 +88,15 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
88 } 88 }
89 89
90 [Test] 90 [Test]
91 public void RemoveForClient() 91 public void TestRemoveForClient()
92 { 92 {
93 TestHelpers.InMethod(); 93 TestHelpers.InMethod();
94// log4net.Config.XmlConfigurator.Configure(); 94// TestHelpers.EnableLogging();
95 95
96 UUID spId = TestHelpers.ParseTail(0x1); 96 UUID spId = TestHelpers.ParseTail(0x1);
97 97
98 SceneHelpers.AddScenePresence(m_scene, spId); 98 SceneHelpers.AddScenePresence(m_scene, spId);
99 m_scene.IncomingCloseAgent(spId, false); 99 m_scene.CloseAgent(spId, false);
100 100
101 // TODO: Add more assertions for the other aspects of event queues 101 // TODO: Add more assertions for the other aspects of event queues
102 Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0)); 102 Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0));
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
index 6ec1115..7b15284 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
@@ -246,8 +246,8 @@ namespace OpenSim.Region.ClientStack.Linden
246 246
247 private Scene m_scene; 247 private Scene m_scene;
248 private MeshCapsDataThrottler m_throttler; 248 private MeshCapsDataThrottler m_throttler;
249 public PollServiceMeshEventArgs(UUID pId, Scene scene) : 249 public PollServiceMeshEventArgs(string uri, UUID pId, Scene scene) :
250 base(null, null, null, null, pId, int.MaxValue) 250 base(null, uri, null, null, null, pId, int.MaxValue)
251 { 251 {
252 m_scene = scene; 252 m_scene = scene;
253 m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene, pId); 253 m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene, pId);
@@ -361,7 +361,7 @@ namespace OpenSim.Region.ClientStack.Linden
361 string capUrl = "/CAPS/" + UUID.Random() + "/"; 361 string capUrl = "/CAPS/" + UUID.Random() + "/";
362 362
363 // Register this as a poll service 363 // Register this as a poll service
364 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(agentID, m_scene); 364 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(capUrl, agentID, m_scene);
365 365
366 args.Type = PollServiceEventArgs.EventType.Mesh; 366 args.Type = PollServiceEventArgs.EventType.Mesh;
367 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); 367 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
index 0570144..e053054 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
@@ -84,6 +84,8 @@ namespace OpenSim.Region.ClientStack.Linden
84 84
85 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>(); 85 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>();
86 86
87 private string m_URL;
88
87 #region ISharedRegionModule Members 89 #region ISharedRegionModule Members
88 90
89 public void Initialise(IConfigSource source) 91 public void Initialise(IConfigSource source)
@@ -215,7 +217,7 @@ namespace OpenSim.Region.ClientStack.Linden
215 private Scene m_scene; 217 private Scene m_scene;
216 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000); 218 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000);
217 public PollServiceTextureEventArgs(UUID pId, Scene scene) : 219 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
218 base(null, null, null, null, pId, int.MaxValue) 220 base(null, "", null, null, null, pId, int.MaxValue)
219 { 221 {
220 m_scene = scene; 222 m_scene = scene;
221 // x is request id, y is userid 223 // x is request id, y is userid
@@ -368,7 +370,11 @@ namespace OpenSim.Region.ClientStack.Linden
368 port = MainServer.Instance.SSLPort; 370 port = MainServer.Instance.SSLPort;
369 protocol = "https"; 371 protocol = "https";
370 } 372 }
371 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); 373 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
374 if (handler != null)
375 handler.RegisterExternalUserCapsHandler(agentID, caps, "GetTexture", capUrl);
376 else
377 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
372 m_pollservices[agentID] = args; 378 m_pollservices[agentID] = args;
373 m_capsDict[agentID] = capUrl; 379 m_capsDict[agentID] = capUrl;
374 } 380 }
@@ -380,13 +386,11 @@ namespace OpenSim.Region.ClientStack.Linden
380 386
381 private void DeregisterCaps(UUID agentID, Caps caps) 387 private void DeregisterCaps(UUID agentID, Caps caps)
382 { 388 {
383 string capUrl;
384 PollServiceTextureEventArgs args; 389 PollServiceTextureEventArgs args;
385 if (m_capsDict.TryGetValue(agentID, out capUrl)) 390
386 { 391 MainServer.Instance.RemoveHTTPHandler("", m_URL);
387 MainServer.Instance.RemoveHTTPHandler("", capUrl); 392 m_capsDict.Remove(agentID);
388 m_capsDict.Remove(agentID); 393
389 }
390 if (m_pollservices.TryGetValue(agentID, out args)) 394 if (m_pollservices.TryGetValue(agentID, out args))
391 { 395 {
392 m_pollservices.Remove(agentID); 396 m_pollservices.Remove(agentID);
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs
index 92805e2..94f8bc1 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs
@@ -155,6 +155,7 @@ namespace OpenSim.Region.ClientStack.Linden
155 Quaternion rotation = Quaternion.Identity; 155 Quaternion rotation = Quaternion.Identity;
156 Vector3 scale = Vector3.Zero; 156 Vector3 scale = Vector3.Zero;
157 int state = 0; 157 int state = 0;
158 int lastattach = 0;
158 159
159 if (r.Type != OSDType.Map) // not a proper req 160 if (r.Type != OSDType.Map) // not a proper req
160 return responsedata; 161 return responsedata;
@@ -224,6 +225,7 @@ namespace OpenSim.Region.ClientStack.Linden
224 225
225 ray_target_id = ObjMap["RayTargetId"].AsUUID(); 226 ray_target_id = ObjMap["RayTargetId"].AsUUID();
226 state = ObjMap["State"].AsInteger(); 227 state = ObjMap["State"].AsInteger();
228 lastattach = ObjMap["LastAttachPoint"].AsInteger();
227 try 229 try
228 { 230 {
229 ray_end = ((OSDArray)ObjMap["RayEnd"]).AsVector3(); 231 ray_end = ((OSDArray)ObjMap["RayEnd"]).AsVector3();
@@ -290,6 +292,7 @@ namespace OpenSim.Region.ClientStack.Linden
290 292
291 //session_id = rm["session_id"].AsUUID(); 293 //session_id = rm["session_id"].AsUUID();
292 state = rm["state"].AsInteger(); 294 state = rm["state"].AsInteger();
295 lastattach = rm["last_attach_point"].AsInteger();
293 try 296 try
294 { 297 {
295 ray_end = ((OSDArray)rm["ray_end"]).AsVector3(); 298 ray_end = ((OSDArray)rm["ray_end"]).AsVector3();
@@ -331,6 +334,7 @@ namespace OpenSim.Region.ClientStack.Linden
331 pbs.ProfileEnd = (ushort)profile_end; 334 pbs.ProfileEnd = (ushort)profile_end;
332 pbs.Scale = scale; 335 pbs.Scale = scale;
333 pbs.State = (byte)state; 336 pbs.State = (byte)state;
337 pbs.LastAttachPoint = (byte)lastattach;
334 338
335 SceneObjectGroup obj = null; ; 339 SceneObjectGroup obj = null; ;
336 340
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
index 55a503e..769fe28 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
@@ -277,6 +277,7 @@ namespace OpenSim.Region.ClientStack.Linden
277 pbs.ProfileEnd = (ushort) obj.ProfileEnd; 277 pbs.ProfileEnd = (ushort) obj.ProfileEnd;
278 pbs.Scale = obj.Scale; 278 pbs.Scale = obj.Scale;
279 pbs.State = (byte) 0; 279 pbs.State = (byte) 0;
280 pbs.LastAttachPoint = (byte) 0;
280 SceneObjectPart prim = new SceneObjectPart(); 281 SceneObjectPart prim = new SceneObjectPart();
281 prim.UUID = UUID.Random(); 282 prim.UUID = UUID.Random();
282 prim.CreatorID = AgentId; 283 prim.CreatorID = AgentId;
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs
index 595d01a..112608b 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.6.*")] 32[assembly: AssemblyVersion("0.8.0.*")]
33 33
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
index 79d56c4..5196368 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
@@ -183,7 +183,7 @@ namespace OpenSim.Region.ClientStack.Linden
183 m_isGod = m_scene.Permissions.IsGod(agentID); 183 m_isGod = m_scene.Permissions.IsGod(agentID);
184 } 184 }
185 185
186 public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 186 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
187 { 187 {
188 StreamReader reader = new StreamReader(request); 188 StreamReader reader = new StreamReader(request);
189 string message = reader.ReadToEnd(); 189 string message = reader.ReadToEnd();
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
index 7d9f935..e4d8a20 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
@@ -68,7 +68,6 @@ namespace OpenSim.Region.ClientStack.Linden
68 /// </summary> 68 /// </summary>
69 private OSDMap m_features = new OSDMap(); 69 private OSDMap m_features = new OSDMap();
70 70
71 private string m_MapImageServerURL = string.Empty;
72 private string m_SearchURL = string.Empty; 71 private string m_SearchURL = string.Empty;
73 private bool m_ExportSupported = false; 72 private bool m_ExportSupported = false;
74 73
@@ -78,15 +77,7 @@ namespace OpenSim.Region.ClientStack.Linden
78 { 77 {
79 IConfig config = source.Configs["SimulatorFeatures"]; 78 IConfig config = source.Configs["SimulatorFeatures"];
80 if (config != null) 79 if (config != null)
81 { 80 {
82 m_MapImageServerURL = config.GetString("MapImageServerURI", string.Empty);
83 if (m_MapImageServerURL != string.Empty)
84 {
85 m_MapImageServerURL = m_MapImageServerURL.Trim();
86 if (!m_MapImageServerURL.EndsWith("/"))
87 m_MapImageServerURL = m_MapImageServerURL + "/";
88 }
89
90 m_SearchURL = config.GetString("SearchServerURI", string.Empty); 81 m_SearchURL = config.GetString("SearchServerURI", string.Empty);
91 82
92 m_ExportSupported = config.GetBoolean("ExportSupported", m_ExportSupported); 83 m_ExportSupported = config.GetBoolean("ExportSupported", m_ExportSupported);
@@ -149,15 +140,16 @@ namespace OpenSim.Region.ClientStack.Linden
149 m_features["PhysicsShapeTypes"] = typesMap; 140 m_features["PhysicsShapeTypes"] = typesMap;
150 141
151 // Extra information for viewers that want to use it 142 // Extra information for viewers that want to use it
152 OSDMap gridServicesMap = new OSDMap(); 143 // TODO: Take these out of here into their respective modules, like map-server-url
153 if (m_MapImageServerURL != string.Empty) 144 OSDMap extrasMap = new OSDMap();
154 gridServicesMap["map-server-url"] = m_MapImageServerURL;
155 if (m_SearchURL != string.Empty) 145 if (m_SearchURL != string.Empty)
156 gridServicesMap["search"] = m_SearchURL; 146 extrasMap["search-server-url"] = m_SearchURL;
157 m_features["GridServices"] = gridServicesMap;
158
159 if (m_ExportSupported) 147 if (m_ExportSupported)
160 m_features["ExportSupported"] = true; 148 extrasMap["ExportSupported"] = true;
149
150 if (extrasMap.Count > 0)
151 m_features["OpenSimExtras"] = extrasMap;
152
161 } 153 }
162 } 154 }
163 155
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
index eca576d..50e9275 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);
@@ -89,9 +96,7 @@ namespace OpenSim.Region.ClientStack.Linden
89 s.EventManager.OnRemovePresence -= DeRegisterPresence; 96 s.EventManager.OnRemovePresence -= DeRegisterPresence;
90 m_BakedTextureModule = null; 97 m_BakedTextureModule = null;
91 m_scene = null; 98 m_scene = null;
92 } 99 }
93
94
95 100
96 public void RegionLoaded(Scene s) 101 public void RegionLoaded(Scene s)
97 { 102 {
@@ -103,44 +108,58 @@ namespace OpenSim.Region.ClientStack.Linden
103 108
104 private void DeRegisterPresence(UUID agentId) 109 private void DeRegisterPresence(UUID agentId)
105 { 110 {
106 ScenePresence presence = null; 111// ScenePresence presence = null;
107 if (m_scene.TryGetScenePresence(agentId, out presence)) 112// if (m_scene.TryGetScenePresence(agentId, out presence))
108 { 113 {
109 presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings; 114// presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings;
110 } 115 }
111 116
112 } 117 }
113 118
114 private void RegisterNewPresence(ScenePresence presence) 119 private void RegisterNewPresence(ScenePresence presence)
115 { 120 {
116 presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings; 121// presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings;
117
118 } 122 }
119 123
120 private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems) 124/* not in use. work done in AvatarFactoryModule ValidateBakedTextureCache() and UpdateBakedTextureCache()
121 { 125 private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
122 int maxCacheitemsLoop = cacheItems.Length;
123 if (maxCacheitemsLoop > AvatarWearable.MAX_WEARABLES)
124 {
125 maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES;
126 m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES);
127 }
128
129 m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
130 if (cacheItems.Length > 0)
131 {
132 m_log.Debug("[Cacheitems]: " + cacheItems.Length);
133 for (int iter = 0; iter < maxCacheitemsLoop; iter++)
134 {
135 m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" +
136 cacheItems[iter].TextureID);
137 }
138
139 ScenePresence p = null;
140 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out p))
141 { 126 {
127 // if cacheItems.Length > 0 viewer is giving us current textures information.
128 // baked ones should had been uploaded and in assets cache as local itens
129
130
131 if (cacheItems.Length == 0)
132 return; // no textures information, nothing to do
133
134 ScenePresence p = null;
135 if (!m_scene.TryGetScenePresence(remoteClient.AgentId, out p))
136 return; // what are we doing if there is no presence to cache for?
137
138 if (p.IsDeleted)
139 return; // does this really work?
140
141 int maxCacheitemsLoop = cacheItems.Length;
142 if (maxCacheitemsLoop > 20)
143 {
144 maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES;
145 m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES);
146 }
147
148 m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
149
150
151 // some nice debug
152 m_log.Debug("[Cacheitems]: " + cacheItems.Length);
153 for (int iter = 0; iter < maxCacheitemsLoop; iter++)
154 {
155 m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" +
156 cacheItems[iter].TextureID);
157 }
158
159 // p.Appearance.WearableCacheItems is in memory primary cashID to textures mapper
142 160
143 WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems; 161 WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems;
162
144 if (existingitems == null) 163 if (existingitems == null)
145 { 164 {
146 if (m_BakedTextureModule != null) 165 if (m_BakedTextureModule != null)
@@ -154,38 +173,22 @@ namespace OpenSim.Region.ClientStack.Linden
154 p.Appearance.WearableCacheItems = savedcache; 173 p.Appearance.WearableCacheItems = savedcache;
155 p.Appearance.WearableCacheItemsDirty = false; 174 p.Appearance.WearableCacheItemsDirty = false;
156 } 175 }
157
158 }
159 /*
160 * The following Catch types DO NOT WORK with m_BakedTextureModule.Get
161 * it jumps to the General Packet Exception Handler if you don't catch Exception!
162 *
163 catch (System.Net.Sockets.SocketException)
164 {
165 cacheItems = null;
166 }
167 catch (WebException)
168 {
169 cacheItems = null;
170 } 176 }
171 catch (InvalidOperationException) 177
172 {
173 cacheItems = null;
174 } */
175 catch (Exception) 178 catch (Exception)
176 { 179 {
177 // The service logs a sufficient error message. 180 // The service logs a sufficient error message.
178 } 181 }
179 182
180 183
181 if (savedcache != null) 184 if (savedcache != null)
182 existingitems = savedcache; 185 existingitems = savedcache;
183 } 186 }
184 } 187 }
188
185 // Existing items null means it's a fully new appearance 189 // Existing items null means it's a fully new appearance
186 if (existingitems == null) 190 if (existingitems == null)
187 { 191 {
188
189 for (int i = 0; i < maxCacheitemsLoop; i++) 192 for (int i = 0; i < maxCacheitemsLoop; i++)
190 { 193 {
191 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) 194 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
@@ -198,7 +201,7 @@ namespace OpenSim.Region.ClientStack.Linden
198 AppearanceManager.DEFAULT_AVATAR_TEXTURE; 201 AppearanceManager.DEFAULT_AVATAR_TEXTURE;
199 continue; 202 continue;
200 } 203 }
201 cacheItems[i].TextureID =face.TextureID; 204 cacheItems[i].TextureID = face.TextureID;
202 if (m_scene.AssetService != null) 205 if (m_scene.AssetService != null)
203 cacheItems[i].TextureAsset = 206 cacheItems[i].TextureAsset =
204 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString()); 207 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
@@ -207,15 +210,10 @@ namespace OpenSim.Region.ClientStack.Linden
207 { 210 {
208 m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length); 211 m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length);
209 } 212 }
210
211
212 } 213 }
213 } 214 }
214 else 215 else
215 216 {
216
217 {
218 // for each uploaded baked texture
219 for (int i = 0; i < maxCacheitemsLoop; i++) 217 for (int i = 0; i < maxCacheitemsLoop; i++)
220 { 218 {
221 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) 219 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
@@ -246,23 +244,24 @@ namespace OpenSim.Region.ClientStack.Linden
246 } 244 }
247 } 245 }
248 } 246 }
249
250
251
252 p.Appearance.WearableCacheItems = cacheItems; 247 p.Appearance.WearableCacheItems = cacheItems;
253
254
255 248
256 if (m_BakedTextureModule != null) 249 if (m_BakedTextureModule != null)
257 { 250 {
258 m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems); 251 m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems);
259 p.Appearance.WearableCacheItemsDirty = true; 252 p.Appearance.WearableCacheItemsDirty = true;
260 253
261 } 254 }
262 } 255 else
263 } 256 p.Appearance.WearableCacheItemsDirty = false;
264 }
265 257
258 for (int iter = 0; iter < maxCacheitemsLoop; iter++)
259 {
260 m_log.Debug("[CacheitemsLeaving] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" +
261 cacheItems[iter].TextureID);
262 }
263 }
264 */
266 public void PostInitialise() 265 public void PostInitialise()
267 { 266 {
268 } 267 }
@@ -280,23 +279,28 @@ namespace OpenSim.Region.ClientStack.Linden
280 279
281 public void RegisterCaps(UUID agentID, Caps caps) 280 public void RegisterCaps(UUID agentID, Caps caps)
282 { 281 {
283 UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler( 282// UUID capID = UUID.Random();
284 caps, m_scene.AssetService, m_persistBakedTextures);
285
286
287
288 caps.RegisterHandler(
289 "UploadBakedTexture",
290 new RestStreamHandler(
291 "POST",
292 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
293 avatarhandler.UploadBakedTexture,
294 "UploadBakedTexture",
295 agentID.ToString()));
296 283
297 284 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
298 285 if (m_URL == "localhost")
286 {
287 UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler(
288 caps, m_scene.AssetService, m_persistBakedTextures);
299 289
290 caps.RegisterHandler(
291 "UploadBakedTexture",
292 new RestStreamHandler(
293 "POST",
294 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
295 avatarhandler.UploadBakedTexture,
296 "UploadBakedTexture",
297 agentID.ToString()));
298
299 }
300 else
301 {
302 caps.RegisterHandler("UploadBakedTexture", m_URL);
303 }
300 } 304 }
301 } 305 }
302} \ No newline at end of file 306}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
index 707cc93..6fc35cd 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
@@ -71,9 +71,13 @@ namespace OpenSim.Region.ClientStack.Linden
71 private IInventoryService m_InventoryService; 71 private IInventoryService m_InventoryService;
72 private ILibraryService m_LibraryService; 72 private ILibraryService m_LibraryService;
73 73
74 private bool m_Enabled;
75
76 private string m_fetchInventoryDescendents2Url;
77 private string m_webFetchInventoryDescendentsUrl;
78
74 private static WebFetchInvDescHandler m_webFetchHandler; 79 private static WebFetchInvDescHandler m_webFetchHandler;
75 80
76 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
77 private static Thread[] m_workerThreads = null; 81 private static Thread[] m_workerThreads = null;
78 82
79 private static DoubleQueue<aPollRequest> m_queue = 83 private static DoubleQueue<aPollRequest> m_queue =
@@ -83,22 +87,45 @@ namespace OpenSim.Region.ClientStack.Linden
83 87
84 public void Initialise(IConfigSource source) 88 public void Initialise(IConfigSource source)
85 { 89 {
90 IConfig config = source.Configs["ClientStack.LindenCaps"];
91 if (config == null)
92 return;
93
94 m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty);
95 m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty);
96
97 if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty)
98 {
99 m_Enabled = true;
100 }
86 } 101 }
87 102
88 public void AddRegion(Scene s) 103 public void AddRegion(Scene s)
89 { 104 {
105 if (!m_Enabled)
106 return;
107
90 m_scene = s; 108 m_scene = s;
91 } 109 }
92 110
93 public void RemoveRegion(Scene s) 111 public void RemoveRegion(Scene s)
94 { 112 {
113 if (!m_Enabled)
114 return;
115
95 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 116 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
96 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; 117
118 foreach (Thread t in m_workerThreads)
119 Watchdog.AbortThread(t.ManagedThreadId);
120
97 m_scene = null; 121 m_scene = null;
98 } 122 }
99 123
100 public void RegionLoaded(Scene s) 124 public void RegionLoaded(Scene s)
101 { 125 {
126 if (!m_Enabled)
127 return;
128
102 m_InventoryService = m_scene.InventoryService; 129 m_InventoryService = m_scene.InventoryService;
103 m_LibraryService = m_scene.LibraryService; 130 m_LibraryService = m_scene.LibraryService;
104 131
@@ -106,7 +133,6 @@ namespace OpenSim.Region.ClientStack.Linden
106 m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService); 133 m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
107 134
108 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 135 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
109 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
110 136
111 if (m_workerThreads == null) 137 if (m_workerThreads == null)
112 { 138 {
@@ -140,12 +166,6 @@ namespace OpenSim.Region.ClientStack.Linden
140 166
141 #endregion 167 #endregion
142 168
143 ~WebFetchInvDescModule()
144 {
145 foreach (Thread t in m_workerThreads)
146 Watchdog.AbortThread(t.ManagedThreadId);
147 }
148
149 private class PollServiceInventoryEventArgs : PollServiceEventArgs 169 private class PollServiceInventoryEventArgs : PollServiceEventArgs
150 { 170 {
151 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 171 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -155,8 +175,8 @@ namespace OpenSim.Region.ClientStack.Linden
155 175
156 private Scene m_scene; 176 private Scene m_scene;
157 177
158 public PollServiceInventoryEventArgs(Scene scene, UUID pId) : 178 public PollServiceInventoryEventArgs(Scene scene, string url, UUID pId) :
159 base(null, null, null, null, pId, int.MaxValue) 179 base(null, url, null, null, null, pId, int.MaxValue)
160 { 180 {
161 m_scene = scene; 181 m_scene = scene;
162 182
@@ -278,53 +298,72 @@ namespace OpenSim.Region.ClientStack.Linden
278 requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); 298 requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null);
279 299
280 lock (responses) 300 lock (responses)
281 responses[requestID] = response; 301 responses[requestID] = response;
282 } 302 }
283 } 303 }
284 304
285 private void RegisterCaps(UUID agentID, Caps caps) 305 private void RegisterCaps(UUID agentID, Caps caps)
286 { 306 {
287 string capUrl = "/CAPS/" + UUID.Random() + "/"; 307 RegisterFetchDescendentsCap(agentID, caps, "FetchInventoryDescendents2", m_fetchInventoryDescendents2Url);
288
289 // Register this as a poll service
290 PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID);
291
292 args.Type = PollServiceEventArgs.EventType.Inventory;
293 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
294
295 string hostName = m_scene.RegionInfo.ExternalHostName;
296 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
297 string protocol = "http";
298
299 if (MainServer.Instance.UseSSL)
300 {
301 hostName = MainServer.Instance.SSLCommonName;
302 port = MainServer.Instance.SSLPort;
303 protocol = "https";
304 }
305 caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
306
307 m_capsDict[agentID] = capUrl;
308 } 308 }
309 309
310 private void DeregisterCaps(UUID agentID, Caps caps) 310 private void RegisterFetchDescendentsCap(UUID agentID, Caps caps, string capName, string url)
311 { 311 {
312 string capUrl; 312 string capUrl;
313 313
314 if (m_capsDict.TryGetValue(agentID, out capUrl)) 314 // disable the cap clause
315 if (url == "")
316 {
317 return;
318 }
319 // handled by the simulator
320 else if (url == "localhost")
321 {
322 capUrl = "/CAPS/" + UUID.Random() + "/";
323
324 // Register this as a poll service
325 PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, capUrl, agentID);
326 args.Type = PollServiceEventArgs.EventType.Inventory;
327
328 caps.RegisterPollHandler(capName, args);
329 }
330 // external handler
331 else
315 { 332 {
316 MainServer.Instance.RemoveHTTPHandler("", capUrl); 333 capUrl = url;
317 m_capsDict.Remove(agentID); 334 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
335 if (handler != null)
336 handler.RegisterExternalUserCapsHandler(agentID,caps,capName,capUrl);
337 else
338 caps.RegisterHandler(capName, capUrl);
318 } 339 }
340
341 // m_log.DebugFormat(
342 // "[FETCH INVENTORY DESCENDENTS2 MODULE]: Registered capability {0} at {1} in region {2} for {3}",
343 // capName, capUrl, m_scene.RegionInfo.RegionName, agentID);
319 } 344 }
320 345
346// private void DeregisterCaps(UUID agentID, Caps caps)
347// {
348// string capUrl;
349//
350// if (m_capsDict.TryGetValue(agentID, out capUrl))
351// {
352// MainServer.Instance.RemoveHTTPHandler("", capUrl);
353// m_capsDict.Remove(agentID);
354// }
355// }
356
321 private void DoInventoryRequests() 357 private void DoInventoryRequests()
322 { 358 {
323 while (true) 359 while (true)
324 { 360 {
361 Watchdog.UpdateThread();
362
325 aPollRequest poolreq = m_queue.Dequeue(); 363 aPollRequest poolreq = m_queue.Dequeue();
326 364
327 poolreq.thepoll.Process(poolreq); 365 if (poolreq != null && poolreq.thepoll != null)
366 poolreq.thepoll.Process(poolreq);
328 } 367 }
329 } 368 }
330 } 369 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
index 3995620..15d6f7f 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
@@ -424,12 +424,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
424 // foreign user is visiting, we need to try again after the first fail to the local 424 // foreign user is visiting, we need to try again after the first fail to the local
425 // asset service. 425 // asset service.
426 string assetServerURL = string.Empty; 426 string assetServerURL = string.Empty;
427 if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL)) 427 if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL) && !string.IsNullOrEmpty(assetServerURL))
428 { 428 {
429 if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("=")) 429 if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("="))
430 assetServerURL = assetServerURL + "/"; 430 assetServerURL = assetServerURL + "/";
431 431
432 m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id); 432// m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id);
433 AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived); 433 AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived);
434 return; 434 return;
435 } 435 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 5ee1596..8a28faf 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -84,6 +84,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
84 public event ModifyTerrain OnModifyTerrain; 84 public event ModifyTerrain OnModifyTerrain;
85 public event Action<IClientAPI> OnRegionHandShakeReply; 85 public event Action<IClientAPI> OnRegionHandShakeReply;
86 public event GenericCall1 OnRequestWearables; 86 public event GenericCall1 OnRequestWearables;
87 public event CachedTextureRequest OnCachedTextureRequest;
87 public event SetAppearance OnSetAppearance; 88 public event SetAppearance OnSetAppearance;
88 public event AvatarNowWearing OnAvatarNowWearing; 89 public event AvatarNowWearing OnAvatarNowWearing;
89 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; 90 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv;
@@ -95,6 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
95 public event Action<IClientAPI, bool> OnCompleteMovementToRegion; 96 public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
96 public event UpdateAgent OnPreAgentUpdate; 97 public event UpdateAgent OnPreAgentUpdate;
97 public event UpdateAgent OnAgentUpdate; 98 public event UpdateAgent OnAgentUpdate;
99 public event UpdateAgent OnAgentCameraUpdate;
98 public event AgentRequestSit OnAgentRequestSit; 100 public event AgentRequestSit OnAgentRequestSit;
99 public event AgentSit OnAgentSit; 101 public event AgentSit OnAgentSit;
100 public event AvatarPickerRequest OnAvatarPickerRequest; 102 public event AvatarPickerRequest OnAvatarPickerRequest;
@@ -335,6 +337,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
335 private bool m_VelocityInterpolate = false; 337 private bool m_VelocityInterpolate = false;
336 private const uint MaxTransferBytesPerPacket = 600; 338 private const uint MaxTransferBytesPerPacket = 600;
337 339
340 private volatile bool m_justEditedTerrain = false;
338 341
339 /// <value> 342 /// <value>
340 /// List used in construction of data blocks for an object update packet. This is to stop us having to 343 /// List used in construction of data blocks for an object update packet. This is to stop us having to
@@ -367,7 +370,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
367 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods 370 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
368 /// cannot retain a reference to it outside of that method. 371 /// cannot retain a reference to it outside of that method.
369 /// </remarks> 372 /// </remarks>
370 private AgentUpdateArgs m_lastAgentUpdateArgs; 373 private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs();
371 374
372 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); 375 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
373 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers 376 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@@ -504,6 +507,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
504 m_udpServer = udpServer; 507 m_udpServer = udpServer;
505 m_udpClient = udpClient; 508 m_udpClient = udpClient;
506 m_udpClient.OnQueueEmpty += HandleQueueEmpty; 509 m_udpClient.OnQueueEmpty += HandleQueueEmpty;
510 m_udpClient.HasUpdates += HandleHasUpdates;
507 m_udpClient.OnPacketStats += PopulateStats; 511 m_udpClient.OnPacketStats += PopulateStats;
508 512
509 m_prioritizer = new Prioritizer(m_scene); 513 m_prioritizer = new Prioritizer(m_scene);
@@ -533,7 +537,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
533 // We still perform a force close inside the sync lock since this is intended to attempt close where 537 // We still perform a force close inside the sync lock since this is intended to attempt close where
534 // there is some unidentified connection problem, not where we have issues due to deadlock 538 // there is some unidentified connection problem, not where we have issues due to deadlock
535 if (!IsActive && !force) 539 if (!IsActive && !force)
540 {
541 m_log.DebugFormat(
542 "[CLIENT]: Not attempting to close inactive client {0} in {1} since force flag is not set",
543 Name, m_scene.Name);
544
536 return; 545 return;
546 }
537 547
538 IsActive = false; 548 IsActive = false;
539 CloseWithoutChecks(sendStop); 549 CloseWithoutChecks(sendStop);
@@ -709,12 +719,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
709 //there is a local handler for this packet type 719 //there is a local handler for this packet type
710 if (pprocessor.Async) 720 if (pprocessor.Async)
711 { 721 {
722 ClientInfo cinfo = UDPClient.GetClientInfo();
723 if (!cinfo.AsyncRequests.ContainsKey(packet.Type.ToString()))
724 cinfo.AsyncRequests[packet.Type.ToString()] = 0;
725 cinfo.AsyncRequests[packet.Type.ToString()]++;
726
712 object obj = new AsyncPacketProcess(this, pprocessor.method, packet); 727 object obj = new AsyncPacketProcess(this, pprocessor.method, packet);
713 Util.FireAndForget(ProcessSpecificPacketAsync, obj); 728 Util.FireAndForget(ProcessSpecificPacketAsync, obj);
714 result = true; 729 result = true;
715 } 730 }
716 else 731 else
717 { 732 {
733 ClientInfo cinfo = UDPClient.GetClientInfo();
734 if (!cinfo.SyncRequests.ContainsKey(packet.Type.ToString()))
735 cinfo.SyncRequests[packet.Type.ToString()] = 0;
736 cinfo.SyncRequests[packet.Type.ToString()]++;
737
718 result = pprocessor.method(this, packet); 738 result = pprocessor.method(this, packet);
719 } 739 }
720 } 740 }
@@ -729,6 +749,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
729 } 749 }
730 if (found) 750 if (found)
731 { 751 {
752 ClientInfo cinfo = UDPClient.GetClientInfo();
753 if (!cinfo.GenericRequests.ContainsKey(packet.Type.ToString()))
754 cinfo.GenericRequests[packet.Type.ToString()] = 0;
755 cinfo.GenericRequests[packet.Type.ToString()]++;
756
732 result = method(this, packet); 757 result = method(this, packet);
733 } 758 }
734 } 759 }
@@ -758,7 +783,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
758 783
759 public virtual void Start() 784 public virtual void Start()
760 { 785 {
761 m_scene.AddNewClient(this, PresenceType.User); 786 m_scene.AddNewAgent(this, PresenceType.User);
762 787
763 RefreshGroupMembership(); 788 RefreshGroupMembership();
764 } 789 }
@@ -820,12 +845,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
820 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); 845 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType);
821 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; 846 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes;
822 847
823 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0]; 848 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1];
824// OutPacket(handshake, ThrottleOutPacketType.Task); 849 handshake.RegionInfo4[0] = new RegionHandshakePacket.RegionInfo4Block();
825 // use same as MoveAgentIntoRegion (both should be task ) 850 handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags;
851 handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported
852
826 OutPacket(handshake, ThrottleOutPacketType.Unknown); 853 OutPacket(handshake, ThrottleOutPacketType.Unknown);
827 } 854 }
828 855
856
829 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) 857 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
830 { 858 {
831 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); 859 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete);
@@ -1210,9 +1238,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1210 LLHeightFieldMoronize(map); 1238 LLHeightFieldMoronize(map);
1211 1239
1212 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1240 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1213 layerpack.Header.Reliable = true; 1241
1242 // When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience.
1243 // To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain.
1244 // We also make them unreliable because it's extremely likely that multiple packets will be sent for a terrain patch area
1245 // invalidating previous packets for that area.
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 {
@@ -1405,6 +1456,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1405 1456
1406 mapReply.AgentData.AgentID = AgentId; 1457 mapReply.AgentData.AgentID = AgentId;
1407 mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length]; 1458 mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length];
1459 mapReply.Size = new MapBlockReplyPacket.SizeBlock[mapBlocks2.Length];
1408 mapReply.AgentData.Flags = flag; 1460 mapReply.AgentData.Flags = flag;
1409 1461
1410 for (int i = 0; i < mapBlocks2.Length; i++) 1462 for (int i = 0; i < mapBlocks2.Length; i++)
@@ -1419,6 +1471,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1419 mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags; 1471 mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags;
1420 mapReply.Data[i].Access = mapBlocks2[i].Access; 1472 mapReply.Data[i].Access = mapBlocks2[i].Access;
1421 mapReply.Data[i].Agents = mapBlocks2[i].Agents; 1473 mapReply.Data[i].Agents = mapBlocks2[i].Agents;
1474
1475 // TODO: hookup varregion sim size here
1476 mapReply.Size[i] = new MapBlockReplyPacket.SizeBlock();
1477 mapReply.Size[i].SizeX = 256;
1478 mapReply.Size[i].SizeY = 256;
1422 } 1479 }
1423 OutPacket(mapReply, ThrottleOutPacketType.Land); 1480 OutPacket(mapReply, ThrottleOutPacketType.Land);
1424 } 1481 }
@@ -1580,7 +1637,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1580 OutPacket(pc, ThrottleOutPacketType.Unknown); 1637 OutPacket(pc, ThrottleOutPacketType.Unknown);
1581 } 1638 }
1582 1639
1583 public void SendKillObject(ulong regionHandle, List<uint> localIDs) 1640 public void SendKillObject(List<uint> localIDs)
1584 { 1641 {
1585// foreach (uint id in localIDs) 1642// foreach (uint id in localIDs)
1586// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); 1643// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
@@ -2594,11 +2651,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2594 { 2651 {
2595 AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket(); 2652 AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket();
2596 avatarSitResponse.SitObject.ID = TargetID; 2653 avatarSitResponse.SitObject.ID = TargetID;
2597 if (CameraAtOffset != Vector3.Zero) 2654 avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset;
2598 { 2655 avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset;
2599 avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset;
2600 avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset;
2601 }
2602 avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook; 2656 avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook;
2603 avatarSitResponse.SitTransform.AutoPilot = autopilot; 2657 avatarSitResponse.SitTransform.AutoPilot = autopilot;
2604 avatarSitResponse.SitTransform.SitPosition = OffsetPos; 2658 avatarSitResponse.SitTransform.SitPosition = OffsetPos;
@@ -3630,6 +3684,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3630 avp.Sender.IsTrial = false; 3684 avp.Sender.IsTrial = false;
3631 avp.Sender.ID = agentID; 3685 avp.Sender.ID = agentID;
3632 avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0]; 3686 avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0];
3687
3688 // this need be use in future
3689 // avp.AppearanceData[0].AppearanceVersion = 0;
3690 // avp.AppearanceData[0].CofVersion = 0;
3691
3633 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); 3692 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString());
3634 OutPacket(avp, ThrottleOutPacketType.Task); 3693 OutPacket(avp, ThrottleOutPacketType.Task);
3635 } 3694 }
@@ -3751,7 +3810,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3751 { 3810 {
3752 SceneObjectPart e = (SceneObjectPart)entity; 3811 SceneObjectPart e = (SceneObjectPart)entity;
3753 SceneObjectGroup g = e.ParentGroup; 3812 SceneObjectGroup g = e.ParentGroup;
3754 if (g.RootPart.Shape.State > 30) // HUD 3813 if (g.RootPart.Shape.State > 30 && g.RootPart.Shape.State < 39) // HUD
3755 if (g.OwnerID != AgentId) 3814 if (g.OwnerID != AgentId)
3756 return; // Don't send updates for other people's HUDs 3815 return; // Don't send updates for other people's HUDs
3757 } 3816 }
@@ -3794,12 +3853,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3794 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber); 3853 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
3795 3854
3796 // Count this as a resent packet since we are going to requeue all of the updates contained in it 3855 // Count this as a resent packet since we are going to requeue all of the updates contained in it
3797 Interlocked.Increment(ref m_udpClient.PacketsResent); 3856 Interlocked.Increment(ref m_udpClient.PacketsResent);
3857
3858 // We're not going to worry about interlock yet since its not currently critical that this total count
3859 // is 100% correct
3860 m_udpServer.PacketsResentCount++;
3798 3861
3799 foreach (EntityUpdate update in updates) 3862 foreach (EntityUpdate update in updates)
3800 ResendPrimUpdate(update); 3863 ResendPrimUpdate(update);
3801 } 3864 }
3802 3865
3866// OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
3867// OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>();
3868// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3869// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3870//
3871// OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3872// OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3873// OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3874// OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3875
3876
3803 private void ProcessEntityUpdates(int maxUpdates) 3877 private void ProcessEntityUpdates(int maxUpdates)
3804 { 3878 {
3805 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); 3879 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
@@ -3812,6 +3886,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3812 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); 3886 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3813 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); 3887 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3814 3888
3889// objectUpdateBlocks.Value.Clear();
3890// compressedUpdateBlocks.Value.Clear();
3891// terseUpdateBlocks.Value.Clear();
3892// terseAgentUpdateBlocks.Value.Clear();
3893// objectUpdates.Value.Clear();
3894// compressedUpdates.Value.Clear();
3895// terseUpdates.Value.Clear();
3896// terseAgentUpdates.Value.Clear();
3897
3815 // Check to see if this is a flush 3898 // Check to see if this is a flush
3816 if (maxUpdates <= 0) 3899 if (maxUpdates <= 0)
3817 { 3900 {
@@ -3847,7 +3930,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3847 if (part.ParentGroup.IsAttachment) 3930 if (part.ParentGroup.IsAttachment)
3848 { // Someone else's HUD, why are we getting these? 3931 { // Someone else's HUD, why are we getting these?
3849 if (part.ParentGroup.OwnerID != AgentId && 3932 if (part.ParentGroup.OwnerID != AgentId &&
3850 part.ParentGroup.RootPart.Shape.State > 30) 3933 part.ParentGroup.RootPart.Shape.State > 30 && part.ParentGroup.RootPart.Shape.State < 39)
3851 continue; 3934 continue;
3852 ScenePresence sp; 3935 ScenePresence sp;
3853 // Owner is not in the sim, don't update it to 3936 // Owner is not in the sim, don't update it to
@@ -4140,8 +4223,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4140 4223
4141 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) 4224 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
4142 { 4225 {
4226// if (!m_udpServer.IsRunningOutbound)
4227// return;
4228
4143 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) 4229 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4144 { 4230 {
4231// if (!m_udpServer.IsRunningOutbound)
4232// return;
4233
4145 if (m_maxUpdates == 0 || m_LastQueueFill == 0) 4234 if (m_maxUpdates == 0 || m_LastQueueFill == 0)
4146 { 4235 {
4147 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; 4236 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
@@ -4167,6 +4256,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4167 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); 4256 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit);
4168 } 4257 }
4169 4258
4259 internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories)
4260 {
4261 bool hasUpdates = false;
4262
4263 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4264 {
4265 if (m_entityUpdates.Count > 0)
4266 hasUpdates = true;
4267 else if (m_entityProps.Count > 0)
4268 hasUpdates = true;
4269 }
4270
4271 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
4272 {
4273 if (ImageManager.HasUpdates())
4274 hasUpdates = true;
4275 }
4276
4277 return hasUpdates;
4278 }
4279
4170 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) 4280 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
4171 { 4281 {
4172 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); 4282 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
@@ -4312,6 +4422,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4312 // Count this as a resent packet since we are going to requeue all of the updates contained in it 4422 // Count this as a resent packet since we are going to requeue all of the updates contained in it
4313 Interlocked.Increment(ref m_udpClient.PacketsResent); 4423 Interlocked.Increment(ref m_udpClient.PacketsResent);
4314 4424
4425 // We're not going to worry about interlock yet since its not currently critical that this total count
4426 // is 100% correct
4427 m_udpServer.PacketsResentCount++;
4428
4315 foreach (ObjectPropertyUpdate update in updates) 4429 foreach (ObjectPropertyUpdate update in updates)
4316 ResendPropertyUpdate(update); 4430 ResendPropertyUpdate(update);
4317 } 4431 }
@@ -4499,6 +4613,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4499 SceneObjectPart root = sop.ParentGroup.RootPart; 4613 SceneObjectPart root = sop.ParentGroup.RootPart;
4500 4614
4501 block.TouchName = Util.StringToBytes256(root.TouchName); 4615 block.TouchName = Util.StringToBytes256(root.TouchName);
4616
4617 // SL 3.3.4, at least, appears to read this information as a concatenated byte[] stream of UUIDs but
4618 // it's not yet clear whether this is actually used. If this is done in the future then a pre-cached
4619 // copy is really needed since it's less efficient to be constantly recreating this byte array.
4620// using (MemoryStream memStream = new MemoryStream())
4621// {
4622// using (BinaryWriter binWriter = new BinaryWriter(memStream))
4623// {
4624// for (int i = 0; i < sop.GetNumberOfSides(); i++)
4625// {
4626// Primitive.TextureEntryFace teFace = sop.Shape.Textures.FaceTextures[i];
4627//
4628// UUID textureID;
4629//
4630// if (teFace != null)
4631// textureID = teFace.TextureID;
4632// else
4633// textureID = sop.Shape.Textures.DefaultTexture.TextureID;
4634//
4635// binWriter.Write(textureID.GetBytes());
4636// }
4637//
4638// block.TextureID = memStream.ToArray();
4639// }
4640// }
4641
4502 block.TextureID = new byte[0]; // TextureID ??? 4642 block.TextureID = new byte[0]; // TextureID ???
4503 block.SitName = Util.StringToBytes256(root.SitName); 4643 block.SitName = Util.StringToBytes256(root.SitName);
4504 block.OwnerMask = root.OwnerMask; 4644 block.OwnerMask = root.OwnerMask;
@@ -4744,7 +4884,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4744 float simObjectBonusFactor, int parcelObjectCapacity, int simObjectCapacity, uint regionFlags) 4884 float simObjectBonusFactor, int parcelObjectCapacity, int simObjectCapacity, uint regionFlags)
4745 { 4885 {
4746// m_log.DebugFormat("[LLCLIENTVIEW]: Sending land properties for {0} to {1}", lo.LandData.GlobalID, Name); 4886// m_log.DebugFormat("[LLCLIENTVIEW]: Sending land properties for {0} to {1}", lo.LandData.GlobalID, Name);
4747 4887
4748 LandData landData = lo.LandData; 4888 LandData landData = lo.LandData;
4749 4889
4750 ParcelPropertiesMessage updateMessage = new ParcelPropertiesMessage(); 4890 ParcelPropertiesMessage updateMessage = new ParcelPropertiesMessage();
@@ -4839,7 +4979,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4839 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); 4979 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
4840 if (eq != null) 4980 if (eq != null)
4841 { 4981 {
4842 eq.ParcelProperties(updateMessage, this.AgentId); 4982 OSD message_body = updateMessage.Serialize();
4983 // Add new fields here until OMV has them
4984 OSDMap bodyMap = (OSDMap)message_body;
4985 OSDArray parcelDataArray = (OSDArray)bodyMap["ParcelData"];
4986 OSDMap parcelData = (OSDMap)parcelDataArray[0];
4987 parcelData["SeeAVs"] = OSD.FromBoolean(landData.SeeAVs);
4988 parcelData["AnyAVSounds"] = OSD.FromBoolean(landData.AnyAVSounds);
4989 parcelData["GroupAVSounds"] = OSD.FromBoolean(landData.GroupAVSounds);
4990 OSDMap message = new OSDMap();
4991 message.Add("message", OSD.FromString("ParcelProperties"));
4992 message.Add("body", message_body);
4993 eq.Enqueue (message, this.AgentId);
4994 //eq.ParcelProperties(updateMessage, this.AgentId);
4843 } 4995 }
4844 else 4996 else
4845 { 4997 {
@@ -4877,7 +5029,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4877 5029
4878 public void SendForceClientSelectObjects(List<uint> ObjectIDs) 5030 public void SendForceClientSelectObjects(List<uint> ObjectIDs)
4879 { 5031 {
4880 m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); 5032// m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count);
4881 5033
4882 bool firstCall = true; 5034 bool firstCall = true;
4883 const int MAX_OBJECTS_PER_PACKET = 251; 5035 const int MAX_OBJECTS_PER_PACKET = 251;
@@ -4997,33 +5149,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4997 5149
4998 position = presence.OffsetPosition; 5150 position = presence.OffsetPosition;
4999 rotation = presence.Rotation; 5151 rotation = presence.Rotation;
5000 5152 angularVelocity = presence.AngularVelocity;
5001 if (presence.ParentID != 0) 5153 rotation = presence.Rotation;
5002 {
5003 SceneObjectPart part = m_scene.GetSceneObjectPart(presence.ParentID);
5004 if (part != null && part != part.ParentGroup.RootPart)
5005 {
5006 position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset;
5007 rotation = part.RotationOffset * presence.Rotation;
5008 }
5009 angularVelocity = Vector3.Zero;
5010 }
5011 else
5012 {
5013 angularVelocity = presence.AngularVelocity;
5014 rotation = presence.Rotation;
5015 }
5016 5154
5017 attachPoint = 0; 5155 attachPoint = 0;
5156// m_log.DebugFormat(
5157// "[LLCLIENTVIEW]: Sending terse update to {0} with position {1} in {2}", Name, presence.OffsetPosition, m_scene.Name);
5158
5159 // attachPoint = presence.State; // Core: commented
5018 collisionPlane = presence.CollisionPlane; 5160 collisionPlane = presence.CollisionPlane;
5019 velocity = presence.Velocity; 5161 velocity = presence.Velocity;
5020 acceleration = Vector3.Zero; 5162 acceleration = Vector3.Zero;
5021 5163
5022 // Interestingly, sending this to non-zero will cause the client's avatar to start moving & accelerating
5023 // in that direction, even though we don't model this on the server. Implementing this in the future
5024 // may improve movement smoothness.
5025// acceleration = new Vector3(1, 0, 0);
5026
5027 if (sendTexture) 5164 if (sendTexture)
5028 textureEntry = presence.Appearance.Texture.GetBytes(); 5165 textureEntry = presence.Appearance.Texture.GetBytes();
5029 else 5166 else
@@ -5034,7 +5171,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5034 SceneObjectPart part = (SceneObjectPart)entity; 5171 SceneObjectPart part = (SceneObjectPart)entity;
5035 5172
5036 attachPoint = part.ParentGroup.AttachmentPoint; 5173 attachPoint = part.ParentGroup.AttachmentPoint;
5037 5174 attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16));
5038// m_log.DebugFormat( 5175// m_log.DebugFormat(
5039// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", 5176// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}",
5040// attachPoint, part.Name, part.LocalId, Name); 5177// attachPoint, part.Name, part.LocalId, Name);
@@ -5062,7 +5199,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5062 pos += 4; 5199 pos += 4;
5063 5200
5064 // Avatar/CollisionPlane 5201 // Avatar/CollisionPlane
5065 data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ; 5202 data[pos++] = (byte) attachPoint;
5066 if (avatar) 5203 if (avatar)
5067 { 5204 {
5068 data[pos++] = 1; 5205 data[pos++] = 1;
@@ -5132,17 +5269,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5132 Vector3 offsetPosition = data.OffsetPosition; 5269 Vector3 offsetPosition = data.OffsetPosition;
5133 Quaternion rotation = data.Rotation; 5270 Quaternion rotation = data.Rotation;
5134 uint parentID = data.ParentID; 5271 uint parentID = data.ParentID;
5135 5272
5136 if (parentID != 0) 5273// m_log.DebugFormat(
5137 { 5274// "[LLCLIENTVIEW]: Sending full update to {0} with position {1} in {2}", Name, data.OffsetPosition, m_scene.Name);
5138 SceneObjectPart part = m_scene.GetSceneObjectPart(parentID);
5139 if (part != null && part != part.ParentGroup.RootPart)
5140 {
5141 offsetPosition = part.OffsetPosition + data.OffsetPosition * part.RotationOffset;
5142 rotation = part.RotationOffset * data.Rotation;
5143 parentID = part.ParentGroup.RootPart.LocalId;
5144 }
5145 }
5146 5275
5147 byte[] objectData = new byte[76]; 5276 byte[] objectData = new byte[76];
5148 5277
@@ -5168,7 +5297,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5168 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + 5297 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
5169 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); 5298 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
5170 update.ObjectData = objectData; 5299 update.ObjectData = objectData;
5171 update.ParentID = parentID; 5300
5301 SceneObjectPart parentPart = data.ParentPart;
5302 if (parentPart != null)
5303 update.ParentID = parentPart.ParentGroup.LocalId;
5304 else
5305 update.ParentID = 0;
5306
5172 update.PathCurve = 16; 5307 update.PathCurve = 16;
5173 update.PathScaleX = 100; 5308 update.PathScaleX = 100;
5174 update.PathScaleY = 100; 5309 update.PathScaleY = 100;
@@ -5387,7 +5522,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5387 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); 5522 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject);
5388 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); 5523 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject);
5389 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); 5524 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand);
5390 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply); 5525
5526// AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false);
5527 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, true);
5528
5391 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); 5529 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest);
5392 AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance); 5530 AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance);
5393 AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing); 5531 AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing);
@@ -5448,8 +5586,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5448 AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); 5586 AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false);
5449 AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); 5587 AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false);
5450 AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); 5588 AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false);
5451 AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage); 5589 AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false);
5452 AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest); 5590 AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false);
5453 AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); 5591 AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest);
5454 AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); 5592 AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer);
5455 AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); 5593 AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket);
@@ -5481,7 +5619,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5481 AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); 5619 AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel);
5482 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); 5620 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest);
5483 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); 5621 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false);
5484 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest); 5622 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest, false);
5485 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); 5623 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest);
5486 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); 5624 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false);
5487 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); 5625 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false);
@@ -5594,83 +5732,137 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5594 5732
5595 #region Packet Handlers 5733 #region Packet Handlers
5596 5734
5735 public int TotalAgentUpdates { get; set; }
5736
5597 #region Scene/Avatar 5737 #region Scene/Avatar
5598 5738
5599 private bool HandleAgentUpdate(IClientAPI sener, Packet packet) 5739 // Threshold for body rotation to be a significant agent update
5740 private const float QDELTA = 0.000001f;
5741 // Threshold for camera rotation to be a significant agent update
5742 private const float VDELTA = 0.01f;
5743
5744 /// <summary>
5745 /// This checks the update significance against the last update made.
5746 /// </summary>
5747 /// <remarks>Can only be called by one thread at a time</remarks>
5748 /// <returns></returns>
5749 /// <param name='x'></param>
5750 public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5600 { 5751 {
5601 if (OnAgentUpdate != null) 5752 return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x);
5602 { 5753 }
5603 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5604 5754
5605 #region Packet Session and User Check 5755 /// <summary>
5606 if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId) 5756 /// This checks the movement/state update significance against the last update made.
5607 { 5757 /// </summary>
5608 PacketPool.Instance.ReturnPacket(packet); 5758 /// <remarks>Can only be called by one thread at a time</remarks>
5609 return false; 5759 /// <returns></returns>
5610 } 5760 /// <param name='x'></param>
5611 #endregion 5761 private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5762 {
5763 float qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2);
5764 //qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2);
5765
5766 bool movementSignificant =
5767 (qdelta1 > QDELTA) // significant if body rotation above threshold
5768 // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack
5769 // || (qdelta2 > QDELTA * 10) // significant if head rotation above threshold
5770 || (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed
5771 || (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands
5772 || (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed
5773 || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed
5774 || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed
5775 ;
5776 //if (movementSignificant)
5777 //{
5778 //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}",
5779 // qdelta1, qdelta2);
5780 //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}",
5781 // x.ControlFlags, x.Flags, x.Far, x.State);
5782 //}
5783 return movementSignificant;
5784 }
5612 5785
5613 bool update = false; 5786 /// <summary>
5614 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; 5787 /// This checks the camera update significance against the last update made.
5615 5788 /// </summary>
5616 if (m_lastAgentUpdateArgs != null) 5789 /// <remarks>Can only be called by one thread at a time</remarks>
5617 { 5790 /// <returns></returns>
5618 // These should be ordered from most-likely to 5791 /// <param name='x'></param>
5619 // least likely to change. I've made an initial 5792 private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5620 // guess at that. 5793 {
5621 update = 5794 float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis);
5622 ( 5795 float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter);
5623 (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || 5796 float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis);
5624 (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || 5797 float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis);
5625 (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) ||
5626 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
5627 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
5628 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
5629 (x.ControlFlags != 0) ||
5630 (x.Far != m_lastAgentUpdateArgs.Far) ||
5631 (x.Flags != m_lastAgentUpdateArgs.Flags) ||
5632 (x.State != m_lastAgentUpdateArgs.State) ||
5633 (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) ||
5634 (x.SessionID != m_lastAgentUpdateArgs.SessionID) ||
5635 (x.AgentID != m_lastAgentUpdateArgs.AgentID)
5636 );
5637 }
5638 else
5639 {
5640 m_lastAgentUpdateArgs = new AgentUpdateArgs();
5641 update = true;
5642 }
5643 5798
5644 if (update) 5799 bool cameraSignificant =
5645 { 5800 (vdelta1 > VDELTA) ||
5646// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); 5801 (vdelta2 > VDELTA) ||
5802 (vdelta3 > VDELTA) ||
5803 (vdelta4 > VDELTA)
5804 ;
5647 5805
5648 m_lastAgentUpdateArgs.AgentID = x.AgentID; 5806 //if (cameraSignificant)
5649 m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; 5807 //{
5650 m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; 5808 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}",
5651 m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter; 5809 // x.CameraAtAxis, x.CameraCenter);
5652 m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; 5810 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}",
5653 m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; 5811 // x.CameraLeftAxis, x.CameraUpAxis);
5654 m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags; 5812 //}
5655 m_lastAgentUpdateArgs.Far = x.Far;
5656 m_lastAgentUpdateArgs.Flags = x.Flags;
5657 m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation;
5658 m_lastAgentUpdateArgs.SessionID = x.SessionID;
5659 m_lastAgentUpdateArgs.State = x.State;
5660 5813
5661 UpdateAgent handlerAgentUpdate = OnAgentUpdate; 5814 return cameraSignificant;
5662 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; 5815 }
5663 5816
5664 if (handlerPreAgentUpdate != null) 5817 private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
5665 OnPreAgentUpdate(this, m_lastAgentUpdateArgs); 5818 {
5819 // We got here, which means that something in agent update was significant
5666 5820
5667 if (handlerAgentUpdate != null) 5821 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5668 OnAgentUpdate(this, m_lastAgentUpdateArgs); 5822 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
5669 5823
5670 handlerAgentUpdate = null; 5824 if (x.AgentID != AgentId || x.SessionID != SessionId)
5671 handlerPreAgentUpdate = null; 5825 return false;
5672 } 5826
5673 } 5827 // Before we update the current m_thisAgentUpdateArgs, let's check this again
5828 // to see what exactly changed
5829 bool movement = CheckAgentMovementUpdateSignificance(x);
5830 bool camera = CheckAgentCameraUpdateSignificance(x);
5831
5832 m_thisAgentUpdateArgs.AgentID = x.AgentID;
5833 m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation;
5834 m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
5835 m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter;
5836 m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
5837 m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
5838 m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags;
5839 m_thisAgentUpdateArgs.Far = x.Far;
5840 m_thisAgentUpdateArgs.Flags = x.Flags;
5841 m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation;
5842 m_thisAgentUpdateArgs.SessionID = x.SessionID;
5843 m_thisAgentUpdateArgs.State = x.State;
5844
5845 UpdateAgent handlerAgentUpdate = OnAgentUpdate;
5846 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
5847 UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate;
5848
5849 // Was there a significant movement/state change?
5850 if (movement)
5851 {
5852 if (handlerPreAgentUpdate != null)
5853 OnPreAgentUpdate(this, m_thisAgentUpdateArgs);
5854
5855 if (handlerAgentUpdate != null)
5856 OnAgentUpdate(this, m_thisAgentUpdateArgs);
5857 }
5858 // Was there a significant camera(s) change?
5859 if (camera)
5860 if (handlerAgentCameraUpdate != null)
5861 handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs);
5862
5863 handlerAgentUpdate = null;
5864 handlerPreAgentUpdate = null;
5865 handlerAgentCameraUpdate = null;
5674 5866
5675 PacketPool.Instance.ReturnPacket(packet); 5867 PacketPool.Instance.ReturnPacket(packet);
5676 5868
@@ -6260,6 +6452,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6260 //m_log.Info("[LAND]: LAND:" + modify.ToString()); 6452 //m_log.Info("[LAND]: LAND:" + modify.ToString());
6261 if (modify.ParcelData.Length > 0) 6453 if (modify.ParcelData.Length > 0)
6262 { 6454 {
6455 // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore,
6456 // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit.
6457 m_justEditedTerrain = true; // Prevent terrain packet (Land layer) from being queued, make it unreliable
6263 if (OnModifyTerrain != null) 6458 if (OnModifyTerrain != null)
6264 { 6459 {
6265 for (int i = 0; i < modify.ParcelData.Length; i++) 6460 for (int i = 0; i < modify.ParcelData.Length; i++)
@@ -6275,6 +6470,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6275 } 6470 }
6276 } 6471 }
6277 } 6472 }
6473 m_justEditedTerrain = false; // Queue terrain packet (Land layer) if necessary, make it reliable again
6278 } 6474 }
6279 6475
6280 return true; 6476 return true;
@@ -6285,6 +6481,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6285 Action<IClientAPI> handlerRegionHandShakeReply = OnRegionHandShakeReply; 6481 Action<IClientAPI> handlerRegionHandShakeReply = OnRegionHandShakeReply;
6286 if (handlerRegionHandShakeReply != null) 6482 if (handlerRegionHandShakeReply != null)
6287 { 6483 {
6484 Thread.Sleep(100);
6288 handlerRegionHandShakeReply(this); 6485 handlerRegionHandShakeReply(this);
6289 } 6486 }
6290 6487
@@ -6343,7 +6540,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6343 6540
6344 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length]; 6541 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length];
6345 for (int i=0; i<appear.WearableData.Length;i++) 6542 for (int i=0; i<appear.WearableData.Length;i++)
6346 cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)}; 6543 cacheitems[i] = new WearableCacheItem(){
6544 CacheId = appear.WearableData[i].CacheID,
6545 TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)
6546 };
6347 6547
6348 6548
6349 6549
@@ -6636,6 +6836,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6636 } 6836 }
6637 #endregion 6837 #endregion
6638 6838
6839 if (SceneAgent.IsChildAgent)
6840 {
6841 SendCantSitBecauseChildAgentResponse();
6842 return true;
6843 }
6844
6639 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; 6845 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit;
6640 6846
6641 if (handlerAgentRequestSit != null) 6847 if (handlerAgentRequestSit != null)
@@ -6660,6 +6866,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6660 } 6866 }
6661 #endregion 6867 #endregion
6662 6868
6869 if (SceneAgent.IsChildAgent)
6870 {
6871 SendCantSitBecauseChildAgentResponse();
6872 return true;
6873 }
6874
6663 AgentSit handlerAgentSit = OnAgentSit; 6875 AgentSit handlerAgentSit = OnAgentSit;
6664 if (handlerAgentSit != null) 6876 if (handlerAgentSit != null)
6665 { 6877 {
@@ -6669,6 +6881,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6669 return true; 6881 return true;
6670 } 6882 }
6671 6883
6884 /// <summary>
6885 /// Used when a child agent gets a sit response which should not be fulfilled.
6886 /// </summary>
6887 private void SendCantSitBecauseChildAgentResponse()
6888 {
6889 SendAlertMessage("Try moving closer. Can't sit on object because it is not in the same region as you.");
6890 }
6891
6672 private bool HandleSoundTrigger(IClientAPI sender, Packet Pack) 6892 private bool HandleSoundTrigger(IClientAPI sender, Packet Pack)
6673 { 6893 {
6674 SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack; 6894 SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack;
@@ -7879,129 +8099,145 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7879 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); 8099 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request");
7880 8100
7881 TransferRequestPacket transfer = (TransferRequestPacket)Pack; 8101 TransferRequestPacket transfer = (TransferRequestPacket)Pack;
7882 //m_log.Debug("Transfer Request: " + transfer.ToString());
7883 // Validate inventory transfers
7884 // Has to be done here, because AssetCache can't do it
7885 //
7886 UUID taskID = UUID.Zero; 8102 UUID taskID = UUID.Zero;
7887 if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) 8103 if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem)
7888 { 8104 {
7889 taskID = new UUID(transfer.TransferInfo.Params, 48);
7890 UUID itemID = new UUID(transfer.TransferInfo.Params, 64);
7891 UUID requestID = new UUID(transfer.TransferInfo.Params, 80);
7892
7893// m_log.DebugFormat(
7894// "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}",
7895// requestID, itemID, taskID, Name);
7896
7897 if (!(((Scene)m_scene).Permissions.BypassPermissions())) 8105 if (!(((Scene)m_scene).Permissions.BypassPermissions()))
7898 { 8106 {
7899 if (taskID != UUID.Zero) // Prim 8107 // We're spawning a thread because the permissions check can block this thread
8108 Util.FireAndForget(delegate
7900 { 8109 {
7901 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); 8110 // This requests the asset if needed
8111 HandleSimInventoryTransferRequestWithPermsCheck(sender, transfer);
8112 });
8113 return true;
8114 }
8115 }
8116 else if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate)
8117 {
8118 //TransferRequestPacket does not include covenant uuid?
8119 //get scene covenant uuid
8120 taskID = m_scene.RegionInfo.RegionSettings.Covenant;
8121 }
7902 8122
7903 if (part == null) 8123 // This is non-blocking
7904 { 8124 MakeAssetRequest(transfer, taskID);
7905 m_log.WarnFormat(
7906 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist",
7907 Name, requestID, itemID, taskID);
7908 return true;
7909 }
7910 8125
7911 TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); 8126 return true;
7912 if (tii == null) 8127 }
7913 {
7914 m_log.WarnFormat(
7915 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist",
7916 Name, requestID, itemID, taskID);
7917 return true;
7918 }
7919 8128
7920 if (tii.Type == (int)AssetType.LSLText) 8129 private void HandleSimInventoryTransferRequestWithPermsCheck(IClientAPI sender, TransferRequestPacket transfer)
7921 { 8130 {
7922 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) 8131 UUID taskID = new UUID(transfer.TransferInfo.Params, 48);
7923 return true; 8132 UUID itemID = new UUID(transfer.TransferInfo.Params, 64);
7924 } 8133 UUID requestID = new UUID(transfer.TransferInfo.Params, 80);
7925 else if (tii.Type == (int)AssetType.Notecard)
7926 {
7927 if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId))
7928 return true;
7929 }
7930 else
7931 {
7932 // TODO: Change this code to allow items other than notecards and scripts to be successfully
7933 // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule
7934 if (part.OwnerID != AgentId)
7935 {
7936 m_log.WarnFormat(
7937 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}",
7938 Name, requestID, itemID, taskID, part.OwnerID);
7939 return true;
7940 }
7941 8134
7942 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) 8135 //m_log.DebugFormat(
7943 { 8136 // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}",
7944 m_log.WarnFormat( 8137 // requestID, itemID, taskID, Name);
7945 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set",
7946 Name, requestID, itemID, taskID);
7947 return true;
7948 }
7949 8138
7950 if (tii.OwnerID != AgentId) 8139 //m_log.Debug("Transfer Request: " + transfer.ToString());
7951 { 8140 // Validate inventory transfers
7952 m_log.WarnFormat( 8141 // Has to be done here, because AssetCache can't do it
7953 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}", 8142 //
7954 Name, requestID, itemID, taskID, tii.OwnerID); 8143 if (taskID != UUID.Zero) // Prim
7955 return true; 8144 {
7956 } 8145 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID);
7957 8146
7958 if (( 8147 if (part == null)
7959 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) 8148 {
7960 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) 8149 m_log.WarnFormat(
7961 { 8150 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist",
7962 m_log.WarnFormat( 8151 Name, requestID, itemID, taskID);
7963 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", 8152 return;
7964 Name, requestID, itemID, taskID); 8153 }
7965 return true;
7966 }
7967 8154
7968 if (tii.AssetID != requestID) 8155 TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID);
7969 { 8156 if (tii == null)
7970 m_log.WarnFormat( 8157 {
7971 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", 8158 m_log.WarnFormat(
7972 Name, requestID, itemID, taskID, tii.AssetID); 8159 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist",
7973 return true; 8160 Name, requestID, itemID, taskID);
7974 } 8161 return;
7975 } 8162 }
8163
8164 if (tii.Type == (int)AssetType.LSLText)
8165 {
8166 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId))
8167 return;
8168 }
8169 else if (tii.Type == (int)AssetType.Notecard)
8170 {
8171 if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId))
8172 return;
8173 }
8174 else
8175 {
8176 // TODO: Change this code to allow items other than notecards and scripts to be successfully
8177 // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule
8178 if (part.OwnerID != AgentId)
8179 {
8180 m_log.WarnFormat(
8181 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}",
8182 Name, requestID, itemID, taskID, part.OwnerID);
8183 return;
7976 } 8184 }
7977 else // Agent 8185
8186 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0)
7978 { 8187 {
7979 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); 8188 m_log.WarnFormat(
7980 if (invAccess != null) 8189 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set",
7981 { 8190 Name, requestID, itemID, taskID);
7982 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID)) 8191 return;
7983 return false; 8192 }
7984 } 8193
7985 else 8194 if (tii.OwnerID != AgentId)
7986 { 8195 {
7987 return false; 8196 m_log.WarnFormat(
7988 } 8197 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}",
8198 Name, requestID, itemID, taskID, tii.OwnerID);
8199 return;
8200 }
8201
8202 if ((
8203 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8204 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8205 {
8206 m_log.WarnFormat(
8207 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer",
8208 Name, requestID, itemID, taskID);
8209 return;
8210 }
8211
8212 if (tii.AssetID != requestID)
8213 {
8214 m_log.WarnFormat(
8215 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}",
8216 Name, requestID, itemID, taskID, tii.AssetID);
8217 return;
7989 } 8218 }
7990 } 8219 }
7991 } 8220 }
7992 else 8221 else // Agent
7993 if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate) 8222 {
8223 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
8224 if (invAccess != null)
7994 { 8225 {
7995 //TransferRequestPacket does not include covenant uuid? 8226 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID))
7996 //get scene covenant uuid 8227 return;
7997 taskID = m_scene.RegionInfo.RegionSettings.Covenant;
7998 } 8228 }
8229 else
8230 {
8231 return;
8232 }
8233 }
7999 8234
8235 // Permissions out of the way, let's request the asset
8000 MakeAssetRequest(transfer, taskID); 8236 MakeAssetRequest(transfer, taskID);
8001 8237
8002 return true;
8003 } 8238 }
8004 8239
8240
8005 private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack) 8241 private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack)
8006 { 8242 {
8007 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; 8243 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack;
@@ -11732,8 +11968,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11732 } 11968 }
11733 11969
11734 /// <summary> 11970 /// <summary>
11735 /// Send a response back to a client when it asks the asset server (via the region server) if it has
11736 /// its appearance texture cached.
11737 /// </summary> 11971 /// </summary>
11738 /// <remarks> 11972 /// <remarks>
11739 /// At the moment, we always reply that there is no cached texture. 11973 /// At the moment, we always reply that there is no cached texture.
@@ -11741,6 +11975,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11741 /// <param name="simclient"></param> 11975 /// <param name="simclient"></param>
11742 /// <param name="packet"></param> 11976 /// <param name="packet"></param>
11743 /// <returns></returns> 11977 /// <returns></returns>
11978 // TODO: Convert old handler to use new method
11979 /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11980 {
11981 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11982
11983 if (cachedtex.AgentData.SessionID != SessionId)
11984 return false;
11985
11986
11987 List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>();
11988
11989 for (int i = 0; i < cachedtex.WearableData.Length; i++)
11990 {
11991 CachedTextureRequestArg arg = new CachedTextureRequestArg();
11992 arg.BakedTextureIndex = cachedtex.WearableData[i].TextureIndex;
11993 arg.WearableHashID = cachedtex.WearableData[i].ID;
11994
11995 requestArgs.Add(arg);
11996 }
11997
11998 CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest;
11999 if (handlerCachedTextureRequest != null)
12000 {
12001 handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs);
12002 }
12003
12004 return true;
12005 }*/
12006
11744 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) 12007 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11745 { 12008 {
11746 //m_log.Debug("texture cached: " + packet.ToString()); 12009 //m_log.Debug("texture cached: " + packet.ToString());
@@ -11749,156 +12012,105 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11749 12012
11750 if (cachedtex.AgentData.SessionID != SessionId) 12013 if (cachedtex.AgentData.SessionID != SessionId)
11751 return false; 12014 return false;
11752
11753 12015
11754 // TODO: don't create new blocks if recycling an old packet 12016 // TODO: don't create new blocks if recycling an old packet
11755 cachedresp.AgentData.AgentID = AgentId; 12017 cachedresp.AgentData.AgentID = AgentId;
11756 cachedresp.AgentData.SessionID = m_sessionId; 12018 cachedresp.AgentData.SessionID = m_sessionId;
11757 cachedresp.AgentData.SerialNum = m_cachedTextureSerial; 12019 cachedresp.AgentData.SerialNum = cachedtex.AgentData.SerialNum;
11758 m_cachedTextureSerial++;
11759 cachedresp.WearableData = 12020 cachedresp.WearableData =
11760 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length]; 12021 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
11761 12022
11762 //IAvatarFactoryModule fac = m_scene.RequestModuleInterface<IAvatarFactoryModule>();
11763 // var item = fac.GetBakedTextureFaces(AgentId);
11764 //WearableCacheItem[] items = fac.GetCachedItems(AgentId);
11765
11766 IAssetService cache = m_scene.AssetService;
11767 IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
11768 //bakedTextureModule = null;
11769 int maxWearablesLoop = cachedtex.WearableData.Length; 12023 int maxWearablesLoop = cachedtex.WearableData.Length;
11770 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES) 12024 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES)
11771 maxWearablesLoop = AvatarWearable.MAX_WEARABLES; 12025 maxWearablesLoop = AvatarWearable.MAX_WEARABLES;
11772 12026
11773 if (bakedTextureModule != null && cache != null) 12027 int cacheHits = 0;
11774 {
11775 // We need to make sure the asset stored in the bake is available on this server also by it's assetid before we map it to a Cacheid
11776 12028
11777 WearableCacheItem[] cacheItems = null; 12029 // We need to make sure the asset stored in the bake is available on this server also by it's assetid before we map it to a Cacheid
11778 ScenePresence p = m_scene.GetScenePresence(AgentId);
11779 if (p.Appearance != null)
11780 if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty)
11781 {
11782 try
11783 {
11784 cacheItems = bakedTextureModule.Get(AgentId);
11785 p.Appearance.WearableCacheItems = cacheItems;
11786 p.Appearance.WearableCacheItemsDirty = false;
11787 }
11788 12030
11789 /* 12031 WearableCacheItem[] cacheItems = null;
11790 * The following Catch types DO NOT WORK, it jumps to the General Packet Exception Handler if you don't catch Exception!
11791 *
11792 catch (System.Net.Sockets.SocketException)
11793 {
11794 cacheItems = null;
11795 }
11796 catch (WebException)
11797 {
11798 cacheItems = null;
11799 }
11800 catch (InvalidOperationException)
11801 {
11802 cacheItems = null;
11803 } */
11804 catch (Exception)
11805 {
11806 cacheItems = null;
11807 }
11808
11809 }
11810 else if (p.Appearance.WearableCacheItems != null)
11811 {
11812 cacheItems = p.Appearance.WearableCacheItems;
11813 }
11814 12032
11815 if (cache != null && cacheItems != null) 12033 ScenePresence p = m_scene.GetScenePresence(AgentId);
11816 {
11817 foreach (WearableCacheItem item in cacheItems)
11818 {
11819
11820 if (cache.GetCached(item.TextureID.ToString()) == null)
11821 {
11822 item.TextureAsset.Temporary = true;
11823 cache.Store(item.TextureAsset);
11824 }
11825 12034
12035 if (p != null && p.Appearance != null)
12036 {
12037 cacheItems = p.Appearance.WearableCacheItems;
12038 }
11826 12039
11827 } 12040 if (cacheItems != null)
11828 } 12041 {
11829 12042 for (int i = 0; i < maxWearablesLoop; i++)
11830 if (cacheItems != null)
11831 { 12043 {
11832 12044 int idx = cachedtex.WearableData[i].TextureIndex;
11833 for (int i = 0; i < maxWearablesLoop; i++)
11834 {
11835 WearableCacheItem item =
11836 WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex,cacheItems);
11837 12045
11838 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); 12046 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11839 cachedresp.WearableData[i].TextureIndex= cachedtex.WearableData[i].TextureIndex; 12047 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11840 cachedresp.WearableData[i].HostName = new byte[0]; 12048 cachedresp.WearableData[i].HostName = new byte[0];
11841 if (item != null && cachedtex.WearableData[i].ID == item.CacheId) 12049 if (cachedtex.WearableData[i].ID == cacheItems[idx].CacheId)
11842 { 12050 {
11843 12051 cachedresp.WearableData[i].TextureID = cacheItems[idx].TextureID;
11844 cachedresp.WearableData[i].TextureID = item.TextureID; 12052 cacheHits++;
11845 }
11846 else
11847 {
11848 cachedresp.WearableData[i].TextureID = UUID.Zero;
11849 }
11850 } 12053 }
11851 } 12054 else
11852 else
11853 {
11854 for (int i = 0; i < maxWearablesLoop; i++)
11855 { 12055 {
11856 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11857 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11858 cachedresp.WearableData[i].TextureID = UUID.Zero; 12056 cachedresp.WearableData[i].TextureID = UUID.Zero;
11859 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11860 cachedresp.WearableData[i].HostName = new byte[0];
11861 } 12057 }
11862 } 12058 }
11863 } 12059 }
11864 else 12060 else
11865 { 12061 {
11866 if (cache == null) 12062 for (int i = 0; i < maxWearablesLoop; i++)
11867 { 12063 {
11868 for (int i = 0; i < maxWearablesLoop; i++) 12064 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11869 { 12065 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11870 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); 12066 cachedresp.WearableData[i].TextureID = UUID.Zero;
11871 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; 12067 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11872 cachedresp.WearableData[i].TextureID = UUID.Zero; 12068 cachedresp.WearableData[i].HostName = new byte[0];
11873 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11874 cachedresp.WearableData[i].HostName = new byte[0];
11875 }
11876 } 12069 }
11877 else 12070 }
11878 {
11879 for (int i = 0; i < maxWearablesLoop; i++)
11880 {
11881 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11882 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11883
11884 12071
12072 m_log.DebugFormat("texture cached: hits {0}", cacheHits);
11885 12073
11886 if (cache.GetCached(cachedresp.WearableData[i].TextureID.ToString()) == null)
11887 cachedresp.WearableData[i].TextureID = UUID.Zero;
11888 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11889 else
11890 cachedresp.WearableData[i].TextureID = UUID.Zero;
11891 // UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11892 cachedresp.WearableData[i].HostName = new byte[0];
11893 }
11894 }
11895 }
11896 cachedresp.Header.Zerocoded = true; 12074 cachedresp.Header.Zerocoded = true;
11897 OutPacket(cachedresp, ThrottleOutPacketType.Task); 12075 OutPacket(cachedresp, ThrottleOutPacketType.Task);
11898 12076
11899 return true; 12077 return true;
11900 } 12078 }
11901 12079
12080 /// <summary>
12081 /// Send a response back to a client when it asks the asset server (via the region server) if it has
12082 /// its appearance texture cached.
12083 /// </summary>
12084 /// <param name="avatar"></param>
12085 /// <param name="serial"></param>
12086 /// <param name="cachedTextures"></param>
12087 /// <returns></returns>
12088 public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures)
12089 {
12090 ScenePresence presence = avatar as ScenePresence;
12091 if (presence == null)
12092 return;
12093
12094 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
12095
12096 // TODO: don't create new blocks if recycling an old packet
12097 cachedresp.AgentData.AgentID = m_agentId;
12098 cachedresp.AgentData.SessionID = m_sessionId;
12099 cachedresp.AgentData.SerialNum = serial;
12100 cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cachedTextures.Count];
12101
12102 for (int i = 0; i < cachedTextures.Count; i++)
12103 {
12104 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12105 cachedresp.WearableData[i].TextureIndex = (byte)cachedTextures[i].BakedTextureIndex;
12106 cachedresp.WearableData[i].TextureID = cachedTextures[i].BakedTextureID;
12107 cachedresp.WearableData[i].HostName = new byte[0];
12108 }
12109
12110 cachedresp.Header.Zerocoded = true;
12111 OutPacket(cachedresp, ThrottleOutPacketType.Task);
12112 }
12113
11902 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) 12114 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet)
11903 { 12115 {
11904 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; 12116 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet;
@@ -11924,8 +12136,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11924 if (part == null) 12136 if (part == null)
11925 { 12137 {
11926 // It's a ghost! tell the client to delete it from view. 12138 // It's a ghost! tell the client to delete it from view.
11927 simClient.SendKillObject(Scene.RegionInfo.RegionHandle, 12139 simClient.SendKillObject(new List<uint> { localId });
11928 new List<uint> { localId });
11929 } 12140 }
11930 else 12141 else
11931 { 12142 {
@@ -12299,6 +12510,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12299 12510
12300 shape.PCode = addPacket.ObjectData.PCode; 12511 shape.PCode = addPacket.ObjectData.PCode;
12301 shape.State = addPacket.ObjectData.State; 12512 shape.State = addPacket.ObjectData.State;
12513 shape.LastAttachPoint = addPacket.ObjectData.State;
12302 shape.PathBegin = addPacket.ObjectData.PathBegin; 12514 shape.PathBegin = addPacket.ObjectData.PathBegin;
12303 shape.PathEnd = addPacket.ObjectData.PathEnd; 12515 shape.PathEnd = addPacket.ObjectData.PathEnd;
12304 shape.PathScaleX = addPacket.ObjectData.PathScaleX; 12516 shape.PathScaleX = addPacket.ObjectData.PathScaleX;
@@ -12329,7 +12541,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12329 ClientInfo info = m_udpClient.GetClientInfo(); 12541 ClientInfo info = m_udpClient.GetClientInfo();
12330 12542
12331 info.proxyEP = null; 12543 info.proxyEP = null;
12332 info.agentcircuit = RequestClientInfo(); 12544 if (info.agentcircuit == null)
12545 info.agentcircuit = RequestClientInfo();
12333 12546
12334 return info; 12547 return info;
12335 } 12548 }
@@ -12712,11 +12925,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12712 OutPacket(dialog, ThrottleOutPacketType.Task); 12925 OutPacket(dialog, ThrottleOutPacketType.Task);
12713 } 12926 }
12714 12927
12715 public void StopFlying(ISceneEntity p) 12928 public void SendAgentTerseUpdate(ISceneEntity p)
12716 { 12929 {
12717 if (p is ScenePresence) 12930 if (p is ScenePresence)
12718 { 12931 {
12719 ScenePresence presence = p as ScenePresence; 12932// m_log.DebugFormat(
12933// "[LLCLIENTVIEW]: Immediately sending terse agent update for {0} to {1} in {2}",
12934// p.Name, Name, Scene.Name);
12935
12720 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities 12936 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities
12721 // There's no explicit message to send the client to tell it to stop flying.. it relies on the 12937 // There's no explicit message to send the client to tell it to stop flying.. it relies on the
12722 // velocity, collision plane and avatar height 12938 // velocity, collision plane and avatar height
@@ -12724,34 +12940,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12724 // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air 12940 // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air
12725 // when the avatar stands up 12941 // when the avatar stands up
12726 12942
12727 Vector3 pos = presence.AbsolutePosition;
12728
12729 if (presence.Appearance.AvatarHeight != 127.0f)
12730 pos += new Vector3(0f, 0f, (presence.Appearance.AvatarHeight/6f));
12731 else
12732 pos += new Vector3(0f, 0f, (1.56f/6f));
12733
12734 presence.AbsolutePosition = pos;
12735
12736 // attach a suitable collision plane regardless of the actual situation to force the LLClient to land.
12737 // Collision plane below the avatar's position a 6th of the avatar's height is suitable.
12738 // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a
12739 // certain amount.. because the LLClient wouldn't land in that situation anyway.
12740
12741 // why are we still testing for this really old height value default???
12742 if (presence.Appearance.AvatarHeight != 127.0f)
12743 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - presence.Appearance.AvatarHeight/6f);
12744 else
12745 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f/6f));
12746
12747
12748 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = 12943 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block =
12749 CreateImprovedTerseBlock(p, false); 12944 CreateImprovedTerseBlock(p, false);
12750 12945
12751 const float TIME_DILATION = 1.0f; 12946 const float TIME_DILATION = 1.0f;
12752 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); 12947 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
12753 12948
12754
12755 ImprovedTerseObjectUpdatePacket packet 12949 ImprovedTerseObjectUpdatePacket packet
12756 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( 12950 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
12757 PacketType.ImprovedTerseObjectUpdate); 12951 PacketType.ImprovedTerseObjectUpdate);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
index 073c357..41dd4d1 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
@@ -206,6 +206,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
206 } 206 }
207 } 207 }
208 208
209 public bool HasUpdates()
210 {
211 J2KImage image = GetHighestPriorityImage();
212
213 return image != null && image.IsDecoded;
214 }
215
209 public bool ProcessImageQueue(int packetsToSend) 216 public bool ProcessImageQueue(int packetsToSend)
210 { 217 {
211 int packetsSent = 0; 218 int packetsSent = 0;
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index e52ac37..bd4e617 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -31,6 +31,7 @@ using System.Net;
31using System.Threading; 31using System.Threading;
32using log4net; 32using log4net;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Monitoring;
34using OpenMetaverse; 35using OpenMetaverse;
35using OpenMetaverse.Packets; 36using OpenMetaverse.Packets;
36 37
@@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
81 /// hooked to put more data on the empty queue</summary> 82 /// hooked to put more data on the empty queue</summary>
82 public event QueueEmpty OnQueueEmpty; 83 public event QueueEmpty OnQueueEmpty;
83 84
85 public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates;
86
84 /// <summary>AgentID for this client</summary> 87 /// <summary>AgentID for this client</summary>
85 public readonly UUID AgentID; 88 public readonly UUID AgentID;
86 /// <summary>The remote address of the connected client</summary> 89 /// <summary>The remote address of the connected client</summary>
@@ -161,6 +164,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
161 public bool m_deliverPackets = true; 164 public bool m_deliverPackets = true;
162 165
163 /// <summary> 166 /// <summary>
167 /// This is the percentage of the udp texture queue to add to the task queue since
168 /// textures are now generally handled through http.
169 /// </summary>
170 private double m_cannibalrate = 0.0;
171
172 private ClientInfo m_info = new ClientInfo();
173
174 /// <summary>
164 /// Default constructor 175 /// Default constructor
165 /// </summary> 176 /// </summary>
166 /// <param name="server">Reference to the UDP server this client is connected to</param> 177 /// <param name="server">Reference to the UDP server this client is connected to</param>
@@ -197,6 +208,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
197 // Create an array of token buckets for this clients different throttle categories 208 // Create an array of token buckets for this clients different throttle categories
198 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; 209 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
199 210
211 m_cannibalrate = rates.CannibalizeTextureRate;
212
200 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) 213 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
201 { 214 {
202 ThrottleOutPacketType type = (ThrottleOutPacketType)i; 215 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
@@ -241,20 +254,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
241 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists 254 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists
242 // of pending and needed ACKs for every client every time some method wants information about 255 // of pending and needed ACKs for every client every time some method wants information about
243 // this connection is a recipe for poor performance 256 // this connection is a recipe for poor performance
244 ClientInfo info = new ClientInfo(); 257
245 info.pendingAcks = new Dictionary<uint, uint>(); 258 m_info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
246 info.needAck = new Dictionary<uint, byte[]>(); 259 m_info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
247 260 m_info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
248 info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; 261 m_info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
249 info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; 262 m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
250 info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; 263 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
251 info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; 264 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
252 info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; 265 m_info.totalThrottle = (int)m_throttleCategory.DripRate;
253 info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; 266
254 info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; 267 return m_info;
255 info.totalThrottle = (int)m_throttleCategory.DripRate;
256
257 return info;
258 } 268 }
259 269
260 /// <summary> 270 /// <summary>
@@ -348,6 +358,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
348 texture = Math.Max(texture, LLUDPServer.MTU); 358 texture = Math.Max(texture, LLUDPServer.MTU);
349 asset = Math.Max(asset, LLUDPServer.MTU); 359 asset = Math.Max(asset, LLUDPServer.MTU);
350 360
361 // Since most textures are now delivered through http, make it possible
362 // to cannibalize some of the bw from the texture throttle to use for
363 // the task queue (e.g. object updates)
364 task = task + (int)(m_cannibalrate * texture);
365 texture = (int)((1 - m_cannibalrate) * texture);
366
351 //int total = resend + land + wind + cloud + task + texture + asset; 367 //int total = resend + land + wind + cloud + task + texture + asset;
352 //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}", 368 //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}",
353 // AgentID, resend, land, wind, cloud, task, texture, asset, total); 369 // AgentID, resend, land, wind, cloud, task, texture, asset, total);
@@ -646,15 +662,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
646 /// <param name="categories">Throttle categories to fire the callback for</param> 662 /// <param name="categories">Throttle categories to fire the callback for</param>
647 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) 663 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
648 { 664 {
649 if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) 665// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
666 if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
650 { 667 {
668 m_isQueueEmptyRunning = true;
669
670 int start = Environment.TickCount & Int32.MaxValue;
671 const int MIN_CALLBACK_MS = 30;
672
673 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
674 if (m_nextOnQueueEmpty == 0)
675 m_nextOnQueueEmpty = 1;
676
651 // Use a value of 0 to signal that FireQueueEmpty is running 677 // Use a value of 0 to signal that FireQueueEmpty is running
652 m_nextOnQueueEmpty = 0; 678// m_nextOnQueueEmpty = 0;
653 // Asynchronously run the callback 679
654 Util.FireAndForget(FireQueueEmpty, categories); 680 m_categories = categories;
681
682 if (HasUpdates(m_categories))
683 {
684 // Asynchronously run the callback
685 Util.FireAndForget(FireQueueEmpty, categories);
686 }
687 else
688 {
689 m_isQueueEmptyRunning = false;
690 }
655 } 691 }
656 } 692 }
657 693
694 private bool m_isQueueEmptyRunning;
695 private ThrottleOutPacketTypeFlags m_categories = 0;
696
658 /// <summary> 697 /// <summary>
659 /// Fires the OnQueueEmpty callback and sets the minimum time that it 698 /// Fires the OnQueueEmpty callback and sets the minimum time that it
660 /// can be called again 699 /// can be called again
@@ -664,22 +703,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
664 /// signature</param> 703 /// signature</param>
665 private void FireQueueEmpty(object o) 704 private void FireQueueEmpty(object o)
666 { 705 {
667 const int MIN_CALLBACK_MS = 30; 706// int start = Environment.TickCount & Int32.MaxValue;
707// const int MIN_CALLBACK_MS = 30;
668 708
669 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; 709// if (m_udpServer.IsRunningOutbound)
670 QueueEmpty callback = OnQueueEmpty; 710// {
671 711 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
672 int start = Environment.TickCount & Int32.MaxValue; 712 QueueEmpty callback = OnQueueEmpty;
673 713
674 if (callback != null) 714 if (callback != null)
675 { 715 {
676 try { callback(categories); } 716// if (m_udpServer.IsRunningOutbound)
677 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } 717// {
678 } 718 try { callback(categories); }
719 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
720// }
721 }
722// }
723
724// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
725// if (m_nextOnQueueEmpty == 0)
726// m_nextOnQueueEmpty = 1;
727
728// }
679 729
680 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; 730 m_isQueueEmptyRunning = false;
681 if (m_nextOnQueueEmpty == 0)
682 m_nextOnQueueEmpty = 1;
683 } 731 }
684 internal void ForceThrottleSetting(int throttle, int setting) 732 internal void ForceThrottleSetting(int throttle, int setting)
685 { 733 {
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 4154ef2..a3fdae1 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -34,6 +34,7 @@ using System.Net.Sockets;
34using System.Reflection; 34using System.Reflection;
35using System.Threading; 35using System.Threading;
36using log4net; 36using log4net;
37using NDesk.Options;
37using Nini.Config; 38using Nini.Config;
38using OpenMetaverse.Packets; 39using OpenMetaverse.Packets;
39using OpenSim.Framework; 40using OpenSim.Framework;
@@ -62,20 +63,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP
62 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); 63 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager);
63 } 64 }
64 65
65 public void NetworkStop()
66 {
67 m_udpServer.Stop();
68 }
69
70 public void AddScene(IScene scene) 66 public void AddScene(IScene scene)
71 { 67 {
72 m_udpServer.AddScene(scene); 68 m_udpServer.AddScene(scene);
73 69
74 StatsManager.RegisterStat( 70 StatsManager.RegisterStat(
75 new Stat( 71 new Stat(
72 "ClientLogoutsDueToNoReceives",
73 "Number of times a client has been logged out because no packets were received before the timeout.",
74 "",
75 "",
76 "clientstack",
77 scene.Name,
78 StatType.Pull,
79 MeasuresOfInterest.None,
80 stat => stat.Value = m_udpServer.ClientLogoutsDueToNoReceives,
81 StatVerbosity.Debug));
82
83 StatsManager.RegisterStat(
84 new Stat(
85 "IncomingUDPReceivesCount",
86 "Number of UDP receives performed",
87 "",
88 "",
89 "clientstack",
90 scene.Name,
91 StatType.Pull,
92 MeasuresOfInterest.AverageChangeOverTime,
93 stat => stat.Value = m_udpServer.UdpReceives,
94 StatVerbosity.Debug));
95
96 StatsManager.RegisterStat(
97 new Stat(
76 "IncomingPacketsProcessedCount", 98 "IncomingPacketsProcessedCount",
77 "Number of inbound UDP packets processed", 99 "Number of inbound LL protocol packets processed",
78 "Number of inbound UDP packets processed", 100 "",
79 "", 101 "",
80 "clientstack", 102 "clientstack",
81 scene.Name, 103 scene.Name,
@@ -83,6 +105,86 @@ namespace OpenSim.Region.ClientStack.LindenUDP
83 MeasuresOfInterest.AverageChangeOverTime, 105 MeasuresOfInterest.AverageChangeOverTime,
84 stat => stat.Value = m_udpServer.IncomingPacketsProcessed, 106 stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
85 StatVerbosity.Debug)); 107 StatVerbosity.Debug));
108
109 StatsManager.RegisterStat(
110 new Stat(
111 "IncomingPacketsMalformedCount",
112 "Number of inbound UDP packets that could not be recognized as LL protocol packets.",
113 "",
114 "",
115 "clientstack",
116 scene.Name,
117 StatType.Pull,
118 MeasuresOfInterest.AverageChangeOverTime,
119 stat => stat.Value = m_udpServer.IncomingMalformedPacketCount,
120 StatVerbosity.Info));
121
122 StatsManager.RegisterStat(
123 new Stat(
124 "IncomingPacketsOrphanedCount",
125 "Number of inbound packets that were not initial connections packets and could not be associated with a viewer.",
126 "",
127 "",
128 "clientstack",
129 scene.Name,
130 StatType.Pull,
131 MeasuresOfInterest.AverageChangeOverTime,
132 stat => stat.Value = m_udpServer.IncomingOrphanedPacketCount,
133 StatVerbosity.Info));
134
135 StatsManager.RegisterStat(
136 new Stat(
137 "IncomingPacketsResentCount",
138 "Number of inbound packets that clients indicate are resends.",
139 "",
140 "",
141 "clientstack",
142 scene.Name,
143 StatType.Pull,
144 MeasuresOfInterest.AverageChangeOverTime,
145 stat => stat.Value = m_udpServer.IncomingPacketsResentCount,
146 StatVerbosity.Debug));
147
148 StatsManager.RegisterStat(
149 new Stat(
150 "OutgoingUDPSendsCount",
151 "Number of UDP sends performed",
152 "",
153 "",
154 "clientstack",
155 scene.Name,
156 StatType.Pull,
157 MeasuresOfInterest.AverageChangeOverTime,
158 stat => stat.Value = m_udpServer.UdpSends,
159 StatVerbosity.Debug));
160
161 StatsManager.RegisterStat(
162 new Stat(
163 "OutgoingPacketsResentCount",
164 "Number of packets resent because a client did not acknowledge receipt",
165 "",
166 "",
167 "clientstack",
168 scene.Name,
169 StatType.Pull,
170 MeasuresOfInterest.AverageChangeOverTime,
171 stat => stat.Value = m_udpServer.PacketsResentCount,
172 StatVerbosity.Debug));
173
174 StatsManager.RegisterStat(
175 new Stat(
176 "AverageUDPProcessTime",
177 "Average number of milliseconds taken to process each incoming UDP packet in a sample.",
178 "This is for initial receive processing which is separate from the later client LL packet processing stage.",
179 "ms",
180 "clientstack",
181 scene.Name,
182 StatType.Pull,
183 MeasuresOfInterest.None,
184 stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond,
185// stat =>
186// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, 7),
187 StatVerbosity.Debug));
86 } 188 }
87 189
88 public bool HandlesRegion(Location x) 190 public bool HandlesRegion(Location x)
@@ -107,10 +209,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
107 /// </summary> 209 /// </summary>
108 public class LLUDPServer : OpenSimUDPBase 210 public class LLUDPServer : OpenSimUDPBase
109 { 211 {
212 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
213
110 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> 214 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary>
111 public const int MTU = 1400; 215 public const int MTU = 1400;
112 216
113 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 217 /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary>
218 public int ClientLogoutsDueToNoReceives { get; private set; }
219
220 /// <summary>
221 /// Default packet debug level given to new clients
222 /// </summary>
223 public int DefaultClientPacketDebugLevel { get; set; }
114 224
115 /// <summary>The measured resolution of Environment.TickCount</summary> 225 /// <summary>The measured resolution of Environment.TickCount</summary>
116 public readonly float TickCountResolution; 226 public readonly float TickCountResolution;
@@ -184,6 +294,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
184 protected bool m_sendPing; 294 protected bool m_sendPing;
185 295
186 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); 296 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
297
298 /// <summary>
299 /// Event used to signal when queued packets are available for sending.
300 /// </summary>
301 /// <remarks>
302 /// This allows the outbound loop to only operate when there is data to send rather than continuously polling.
303 /// Some data is sent immediately and not queued. That data would not trigger this event.
304 /// </remarks>
305 private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
306
187 private Pool<IncomingPacket> m_incomingPacketPool; 307 private Pool<IncomingPacket> m_incomingPacketPool;
188 308
189 /// <summary> 309 /// <summary>
@@ -204,7 +324,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
204 324
205 public Socket Server { get { return null; } } 325 public Socket Server { get { return null; } }
206 326
207 private int m_malformedCount = 0; // Guard against a spamming attack 327 /// <summary>
328 /// Record how many packets have been resent
329 /// </summary>
330 internal int PacketsResentCount { get; set; }
331
332 /// <summary>
333 /// Record how many packets have been sent
334 /// </summary>
335 internal int PacketsSentCount { get; set; }
336
337 /// <summary>
338 /// Record how many incoming packets are indicated as resends by clients.
339 /// </summary>
340 internal int IncomingPacketsResentCount { get; set; }
341
342 /// <summary>
343 /// Record how many inbound packets could not be recognized as LLUDP packets.
344 /// </summary>
345 public int IncomingMalformedPacketCount { get; private set; }
346
347 /// <summary>
348 /// Record how many inbound packets could not be associated with a simulator circuit.
349 /// </summary>
350 public int IncomingOrphanedPacketCount { get; private set; }
208 351
209 /// <summary> 352 /// <summary>
210 /// Record current outgoing client for monitoring purposes. 353 /// Record current outgoing client for monitoring purposes.
@@ -461,6 +604,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
461 m_scene = (Scene)scene; 604 m_scene = (Scene)scene;
462 m_location = new Location(m_scene.RegionInfo.RegionHandle); 605 m_location = new Location(m_scene.RegionInfo.RegionHandle);
463 606
607 StatsManager.RegisterStat(
608 new Stat(
609 "InboxPacketsCount",
610 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
611 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
612 "",
613 "clientstack",
614 scene.Name,
615 StatType.Pull,
616 MeasuresOfInterest.AverageChangeOverTime,
617 stat => stat.Value = packetInbox.Count,
618 StatVerbosity.Debug));
619
464 // XXX: These stats are also pool stats but we register them separately since they are currently not 620 // XXX: These stats are also pool stats but we register them separately since they are currently not
465 // turned on and off by EnablePools()/DisablePools() 621 // turned on and off by EnablePools()/DisablePools()
466 StatsManager.RegisterStat( 622 StatsManager.RegisterStat(
@@ -521,6 +677,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
521 EnablePoolStats(); 677 EnablePoolStats();
522 678
523 MainConsole.Instance.Commands.AddCommand( 679 MainConsole.Instance.Commands.AddCommand(
680 "Debug", false, "debug lludp packet",
681 "debug lludp packet [--default] <level> [<avatar-first-name> <avatar-last-name>]",
682 "Turn on packet debugging",
683 "If level > 255 then all incoming and outgoing packets are logged.\n"
684 + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n"
685 + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n"
686 + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n"
687 + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n"
688 + "If level <= 0 then no packets are logged.\n"
689 + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n"
690 + "In this case, you cannot also specify an avatar name.\n"
691 + "If an avatar name is given then only packets from that avatar are logged.",
692 HandlePacketCommand);
693
694 MainConsole.Instance.Commands.AddCommand(
524 "Debug", 695 "Debug",
525 false, 696 false,
526 "debug lludp start", 697 "debug lludp start",
@@ -559,10 +730,78 @@ namespace OpenSim.Region.ClientStack.LindenUDP
559 "debug lludp status", 730 "debug lludp status",
560 "Return status of LLUDP packet processing.", 731 "Return status of LLUDP packet processing.",
561 HandleStatusCommand); 732 HandleStatusCommand);
733
734 MainConsole.Instance.Commands.AddCommand(
735 "Debug",
736 false,
737 "debug lludp toggle agentupdate",
738 "debug lludp toggle agentupdate",
739 "Toggle whether agentupdate packets are processed or simply discarded.",
740 HandleAgentUpdateCommand);
741 }
742
743 private void HandlePacketCommand(string module, string[] args)
744 {
745 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
746 return;
747
748 bool setAsDefaultLevel = false;
749 OptionSet optionSet = new OptionSet().Add("default", o => setAsDefaultLevel = o != null);
750 List<string> filteredArgs = optionSet.Parse(args);
751
752 string name = null;
753
754 if (filteredArgs.Count == 6)
755 {
756 if (!setAsDefaultLevel)
757 {
758 name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]);
759 }
760 else
761 {
762 MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default logging level");
763 return;
764 }
765 }
766
767 if (filteredArgs.Count > 3)
768 {
769 int newDebug;
770 if (int.TryParse(filteredArgs[3], out newDebug))
771 {
772 if (setAsDefaultLevel)
773 {
774 DefaultClientPacketDebugLevel = newDebug;
775 MainConsole.Instance.OutputFormat(
776 "Debug packet debug for new clients set to {0} in {1}", DefaultClientPacketDebugLevel, m_scene.Name);
777 }
778 else
779 {
780 m_scene.ForEachScenePresence(sp =>
781 {
782 if (name == null || sp.Name == name)
783 {
784 MainConsole.Instance.OutputFormat(
785 "Packet debug for {0} ({1}) set to {2} in {3}",
786 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name);
787
788 sp.ControllingClient.DebugPacketLevel = newDebug;
789 }
790 });
791 }
792 }
793 else
794 {
795 MainConsole.Instance.Output("Usage: debug lludp packet [--default] 0..255 [<first-name> <last-name>]");
796 }
797 }
562 } 798 }
563 799
564 private void HandleStartCommand(string module, string[] args) 800 private void HandleStartCommand(string module, string[] args)
565 { 801 {
802 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
803 return;
804
566 if (args.Length != 4) 805 if (args.Length != 4)
567 { 806 {
568 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); 807 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
@@ -580,6 +819,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
580 819
581 private void HandleStopCommand(string module, string[] args) 820 private void HandleStopCommand(string module, string[] args)
582 { 821 {
822 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
823 return;
824
583 if (args.Length != 4) 825 if (args.Length != 4)
584 { 826 {
585 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); 827 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
@@ -597,6 +839,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
597 839
598 private void HandlePoolCommand(string module, string[] args) 840 private void HandlePoolCommand(string module, string[] args)
599 { 841 {
842 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
843 return;
844
600 if (args.Length != 4) 845 if (args.Length != 4)
601 { 846 {
602 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); 847 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
@@ -627,8 +872,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
627 } 872 }
628 } 873 }
629 874
875 bool m_discardAgentUpdates;
876
877 private void HandleAgentUpdateCommand(string module, string[] args)
878 {
879 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
880 return;
881
882 m_discardAgentUpdates = !m_discardAgentUpdates;
883
884 MainConsole.Instance.OutputFormat(
885 "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name);
886 }
887
630 private void HandleStatusCommand(string module, string[] args) 888 private void HandleStatusCommand(string module, string[] args)
631 { 889 {
890 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
891 return;
892
632 MainConsole.Instance.OutputFormat( 893 MainConsole.Instance.OutputFormat(
633 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); 894 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled");
634 895
@@ -636,6 +897,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
636 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); 897 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
637 898
638 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); 899 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off");
900
901 MainConsole.Instance.OutputFormat(
902 "Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel);
639 } 903 }
640 904
641 public bool HandlesRegion(Location x) 905 public bool HandlesRegion(Location x)
@@ -643,44 +907,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP
643 return x == m_location; 907 return x == m_location;
644 } 908 }
645 909
646 public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) 910// public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
647 { 911// {
648 // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way 912// // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way
649 if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting) 913// if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting)
650 allowSplitting = false; 914// allowSplitting = false;
651 915//
652 if (allowSplitting && packet.HasVariableBlocks) 916// if (allowSplitting && packet.HasVariableBlocks)
653 { 917// {
654 byte[][] datas = packet.ToBytesMultiple(); 918// byte[][] datas = packet.ToBytesMultiple();
655 int packetCount = datas.Length; 919// int packetCount = datas.Length;
656 920//
657 if (packetCount < 1) 921// if (packetCount < 1)
658 m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length); 922// m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length);
659 923//
660 for (int i = 0; i < packetCount; i++) 924// for (int i = 0; i < packetCount; i++)
661 { 925// {
662 byte[] data = datas[i]; 926// byte[] data = datas[i];
663 m_scene.ForEachClient( 927// m_scene.ForEachClient(
664 delegate(IClientAPI client) 928// delegate(IClientAPI client)
665 { 929// {
666 if (client is LLClientView) 930// if (client is LLClientView)
667 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); 931// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
668 } 932// }
669 ); 933// );
670 } 934// }
671 } 935// }
672 else 936// else
673 { 937// {
674 byte[] data = packet.ToBytes(); 938// byte[] data = packet.ToBytes();
675 m_scene.ForEachClient( 939// m_scene.ForEachClient(
676 delegate(IClientAPI client) 940// delegate(IClientAPI client)
677 { 941// {
678 if (client is LLClientView) 942// if (client is LLClientView)
679 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); 943// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
680 } 944// }
681 ); 945// );
682 } 946// }
683 } 947// }
684 948
685 /// <summary> 949 /// <summary>
686 /// Start the process of sending a packet to the client. 950 /// Start the process of sending a packet to the client.
@@ -700,6 +964,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
700 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) 964 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
701 allowSplitting = false; 965 allowSplitting = false;
702 966
967 bool packetQueued = false;
968
703 if (allowSplitting && packet.HasVariableBlocks) 969 if (allowSplitting && packet.HasVariableBlocks)
704 { 970 {
705 byte[][] datas = packet.ToBytesMultiple(); 971 byte[][] datas = packet.ToBytesMultiple();
@@ -711,16 +977,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
711 for (int i = 0; i < packetCount; i++) 977 for (int i = 0; i < packetCount; i++)
712 { 978 {
713 byte[] data = datas[i]; 979 byte[] data = datas[i];
714 SendPacketData(udpClient, data, packet.Type, category, method); 980
981 if (!SendPacketData(udpClient, data, packet.Type, category, method))
982 packetQueued = true;
715 } 983 }
716 } 984 }
717 else 985 else
718 { 986 {
719 byte[] data = packet.ToBytes(); 987 byte[] data = packet.ToBytes();
720 SendPacketData(udpClient, data, packet.Type, category, method); 988 packetQueued = SendPacketData(udpClient, data, packet.Type, category, method);
721 } 989 }
722 990
723 PacketPool.Instance.ReturnPacket(packet); 991 PacketPool.Instance.ReturnPacket(packet);
992
993 if (packetQueued)
994 m_dataPresentEvent.Set();
724 } 995 }
725 996
726 /// <summary> 997 /// <summary>
@@ -734,7 +1005,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
734 /// The method to call if the packet is not acked by the client. If null, then a standard 1005 /// The method to call if the packet is not acked by the client. If null, then a standard
735 /// resend of the packet is done. 1006 /// resend of the packet is done.
736 /// </param> 1007 /// </param>
737 public void SendPacketData( 1008 /// <returns>true if the data was sent immediately, false if it was queued for sending</returns>
1009 public bool SendPacketData(
738 LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method) 1010 LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
739 { 1011 {
740 int dataLength = data.Length; 1012 int dataLength = data.Length;
@@ -807,7 +1079,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
807 // packet so that it isn't sent before a queued update packet. 1079 // packet so that it isn't sent before a queued update packet.
808 bool requestQueue = type == PacketType.KillObject; 1080 bool requestQueue = type == PacketType.KillObject;
809 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority)) 1081 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority))
1082 {
810 SendPacketFinal(outgoingPacket); 1083 SendPacketFinal(outgoingPacket);
1084 return true;
1085 }
1086
1087 return false;
811 1088
812 #endregion Queue or Send 1089 #endregion Queue or Send
813 } 1090 }
@@ -883,7 +1160,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 1160 // 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. 1161 // 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. 1162 // This is the same as processing as the async process of a logout request.
886 Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); 1163 Util.FireAndForget(o => DeactivateClientDueToTimeout(client, timeoutTicks));
887 1164
888 return; 1165 return;
889 } 1166 }
@@ -988,6 +1265,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
988 else 1265 else
989 { 1266 {
990 Interlocked.Increment(ref udpClient.PacketsResent); 1267 Interlocked.Increment(ref udpClient.PacketsResent);
1268
1269 // We're not going to worry about interlock yet since its not currently critical that this total count
1270 // is 100% correct
1271 PacketsResentCount++;
991 } 1272 }
992 1273
993 #endregion Sequence Number Assignment 1274 #endregion Sequence Number Assignment
@@ -995,6 +1276,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
995 // Stats tracking 1276 // Stats tracking
996 Interlocked.Increment(ref udpClient.PacketsSent); 1277 Interlocked.Increment(ref udpClient.PacketsSent);
997 1278
1279 // We're not going to worry about interlock yet since its not currently critical that this total count
1280 // is 100% correct
1281 PacketsSentCount++;
1282
998 // Put the UDP payload on the wire 1283 // Put the UDP payload on the wire
999 AsyncBeginSend(buffer); 1284 AsyncBeginSend(buffer);
1000 1285
@@ -1002,6 +1287,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1002 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; 1287 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
1003 } 1288 }
1004 1289
1290 private void RecordMalformedInboundPacket(IPEndPoint endPoint)
1291 {
1292// if (m_malformedCount < 100)
1293// m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1294
1295 IncomingMalformedPacketCount++;
1296
1297 if ((IncomingMalformedPacketCount % 10000) == 0)
1298 m_log.WarnFormat(
1299 "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}",
1300 IncomingMalformedPacketCount, endPoint);
1301 }
1302
1005 public override void PacketReceived(UDPPacketBuffer buffer) 1303 public override void PacketReceived(UDPPacketBuffer buffer)
1006 { 1304 {
1007 // Debugging/Profiling 1305 // Debugging/Profiling
@@ -1023,6 +1321,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1023// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", 1321// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
1024// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 1322// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1025 1323
1324 RecordMalformedInboundPacket(endPoint);
1325
1026 return; // Drop undersized packet 1326 return; // Drop undersized packet
1027 } 1327 }
1028 1328
@@ -1041,6 +1341,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1041// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", 1341// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}",
1042// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 1342// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1043 1343
1344 RecordMalformedInboundPacket(endPoint);
1345
1044 return; // Malformed header 1346 return; // Malformed header
1045 } 1347 }
1046 1348
@@ -1056,34 +1358,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1056 // Only allocate a buffer for zerodecoding if the packet is zerocoded 1358 // Only allocate a buffer for zerodecoding if the packet is zerocoded
1057 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 1359 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
1058 } 1360 }
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) 1361 catch (Exception e)
1071 { 1362 {
1072 if (m_malformedCount < 100) 1363 if (IncomingMalformedPacketCount < 100)
1073 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); 1364 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 } 1365 }
1080 1366
1081 // Fail-safe check 1367 // Fail-safe check
1082 if (packet == null) 1368 if (packet == null)
1083 { 1369 {
1084 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:", 1370 if (IncomingMalformedPacketCount < 100)
1085 buffer.DataLength, buffer.RemoteEndPoint); 1371 {
1086 m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); 1372 m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:",
1373 buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
1374 }
1375
1376 RecordMalformedInboundPacket(endPoint);
1377
1087 return; 1378 return;
1088 } 1379 }
1089 1380
@@ -1127,12 +1418,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1127 queue.Enqueue(buffer); 1418 queue.Enqueue(buffer);
1128 return; 1419 return;
1129 } 1420 }
1421 else if (packet.Type == PacketType.CompleteAgentMovement)
1422 {
1423 // Send ack straight away to let the viewer know that we got it.
1424 SendAckImmediate(endPoint, packet.Header.Sequence);
1425
1426 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1427 // buffer.
1428 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1429
1430 Util.FireAndForget(HandleCompleteMovementIntoRegion, array);
1431
1432 return;
1433 }
1130 } 1434 }
1131 1435
1132 // Determine which agent this packet came from 1436 // Determine which agent this packet came from
1133 if (client == null || !(client is LLClientView)) 1437 if (client == null || !(client is LLClientView))
1134 { 1438 {
1135 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1439 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1440
1441 IncomingOrphanedPacketCount++;
1442
1443 if ((IncomingOrphanedPacketCount % 10000) == 0)
1444 m_log.WarnFormat(
1445 "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}",
1446 IncomingOrphanedPacketCount, endPoint);
1447
1136 return; 1448 return;
1137 } 1449 }
1138 1450
@@ -1211,6 +1523,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1211 1523
1212 #region Incoming Packet Accounting 1524 #region Incoming Packet Accounting
1213 1525
1526 // We're not going to worry about interlock yet since its not currently critical that this total count
1527 // is 100% correct
1528 if (packet.Header.Resent)
1529 IncomingPacketsResentCount++;
1530
1214 // Check the archive of received reliable packet IDs to see whether we already received this packet 1531 // Check the archive of received reliable packet IDs to see whether we already received this packet
1215 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence)) 1532 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
1216 { 1533 {
@@ -1233,6 +1550,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1233 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); 1550 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
1234 #endregion BinaryStats 1551 #endregion BinaryStats
1235 1552
1553 if (packet.Type == PacketType.AgentUpdate)
1554 {
1555 if (m_discardAgentUpdates)
1556 return;
1557
1558 ((LLClientView)client).TotalAgentUpdates++;
1559
1560 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
1561
1562 LLClientView llClient = client as LLClientView;
1563 if (agentUpdate.AgentData.SessionID != client.SessionId
1564 || agentUpdate.AgentData.AgentID != client.AgentId
1565 || !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) )
1566 {
1567 PacketPool.Instance.ReturnPacket(packet);
1568 return;
1569 }
1570 }
1571
1236 #region Ping Check Handling 1572 #region Ping Check Handling
1237 1573
1238 if (packet.Type == PacketType.StartPingCheck) 1574 if (packet.Type == PacketType.StartPingCheck)
@@ -1414,19 +1750,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1414 endPoint, 1750 endPoint,
1415 sessionInfo); 1751 sessionInfo);
1416 1752
1417 // Send ack straight away to let the viewer know that the connection is active.
1418 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
1419 // circuit code to the existing child agent. This is not particularly obvious.
1420 SendAckImmediate(endPoint, uccp.Header.Sequence);
1421
1422 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1423 if (client != null)
1424 client.SceneAgent.SendInitialDataToMe();
1425
1426 // Now we know we can handle more data 1753 // Now we know we can handle more data
1427 Thread.Sleep(200); 1754// Thread.Sleep(200);
1428 1755
1429 // Obtain the queue and remove it from the cache 1756 // Obtain the pending queue and remove it from the cache
1430 Queue<UDPPacketBuffer> queue = null; 1757 Queue<UDPPacketBuffer> queue = null;
1431 1758
1432 lock (m_pendingCache) 1759 lock (m_pendingCache)
@@ -1448,6 +1775,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1448 PacketReceived(buf); 1775 PacketReceived(buf);
1449 } 1776 }
1450 queue = null; 1777 queue = null;
1778
1779 // Send ack straight away to let the viewer know that the connection is active.
1780 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
1781 // circuit code to the existing child agent. This is not particularly obvious.
1782 SendAckImmediate(endPoint, uccp.Header.Sequence);
1783
1784 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1785 if (client != null)
1786 {
1787 AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1788 bool tp = (aCircuit.teleportFlags > 0);
1789 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from
1790 if (!tp)
1791 client.SceneAgent.SendInitialDataToMe();
1792 }
1451 } 1793 }
1452 else 1794 else
1453 { 1795 {
@@ -1476,6 +1818,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1476 } 1818 }
1477 } 1819 }
1478 1820
1821 private void HandleCompleteMovementIntoRegion(object o)
1822 {
1823 IPEndPoint endPoint = null;
1824 IClientAPI client = null;
1825
1826 try
1827 {
1828 object[] array = (object[])o;
1829 endPoint = (IPEndPoint)array[0];
1830 CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1];
1831
1832 m_log.DebugFormat(
1833 "[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, m_scene.Name);
1834
1835 // Determine which agent this packet came from
1836 // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination
1837 // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode
1838 // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these
1839 // packets asynchronously, we need to account for this thread proceeding more quickly than the
1840 // UseCircuitCode thread.
1841 int count = 40;
1842 while (count-- > 0)
1843 {
1844 if (m_scene.TryGetClient(endPoint, out client))
1845 {
1846 if (!client.IsActive)
1847 {
1848 // This check exists to catch a condition where the client has been closed by another thread
1849 // but has not yet been removed from the client manager (and possibly a new connection has
1850 // not yet been established).
1851 m_log.DebugFormat(
1852 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.",
1853 endPoint, client.Name, m_scene.Name);
1854 }
1855 else if (client.SceneAgent == null)
1856 {
1857 // This check exists to catch a condition where the new client has been added to the client
1858 // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too
1859 // eager, then the new ScenePresence may not have registered a listener for this messsage
1860 // before we try to process it.
1861 // XXX: A better long term fix may be to add the SceneAgent before the client is added to
1862 // the client manager
1863 m_log.DebugFormat(
1864 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.",
1865 endPoint, client.Name, m_scene.Name);
1866 }
1867 else
1868 {
1869 break;
1870 }
1871 }
1872 else
1873 {
1874 m_log.DebugFormat(
1875 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.",
1876 endPoint, m_scene.Name);
1877 }
1878
1879 Thread.Sleep(200);
1880 }
1881
1882 if (client == null)
1883 {
1884 m_log.DebugFormat(
1885 "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.",
1886 endPoint, m_scene.Name);
1887
1888 return;
1889 }
1890 else if (!client.IsActive || client.SceneAgent == null)
1891 {
1892 // This check exists to catch a condition where the client has been closed by another thread
1893 // but has not yet been removed from the client manager.
1894 // The packet could be simply ignored but it is useful to know if this condition occurred for other debugging
1895 // purposes.
1896 m_log.DebugFormat(
1897 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.",
1898 endPoint, client.Name, m_scene.Name);
1899
1900 return;
1901 }
1902
1903 IncomingPacket incomingPacket1;
1904
1905 // Inbox insertion
1906 if (UsePools)
1907 {
1908 incomingPacket1 = m_incomingPacketPool.GetObject();
1909 incomingPacket1.Client = (LLClientView)client;
1910 incomingPacket1.Packet = packet;
1911 }
1912 else
1913 {
1914 incomingPacket1 = new IncomingPacket((LLClientView)client, packet);
1915 }
1916
1917 packetInbox.Enqueue(incomingPacket1);
1918 }
1919 catch (Exception e)
1920 {
1921 m_log.ErrorFormat(
1922 "[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1923 endPoint != null ? endPoint.ToString() : "n/a",
1924 client != null ? client.Name : "unknown",
1925 client != null ? client.AgentId.ToString() : "unknown",
1926 e.Message,
1927 e.StackTrace);
1928 }
1929 }
1930
1479 /// <summary> 1931 /// <summary>
1480 /// Send an ack immediately to the given endpoint. 1932 /// Send an ack immediately to the given endpoint.
1481 /// </summary> 1933 /// </summary>
@@ -1544,6 +1996,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1544 1996
1545 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 1997 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1546 client.OnLogout += LogoutHandler; 1998 client.OnLogout += LogoutHandler;
1999 client.DebugPacketLevel = DefaultClientPacketDebugLevel;
1547 2000
1548 ((LLClientView)client).DisableFacelights = m_disableFacelights; 2001 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1549 2002
@@ -1562,21 +2015,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1562 /// regular client pings. 2015 /// regular client pings.
1563 /// </remarks> 2016 /// </remarks>
1564 /// <param name='client'></param> 2017 /// <param name='client'></param>
1565 private void DeactivateClientDueToTimeout(LLClientView client) 2018 /// <param name='timeoutTicks'></param>
2019 private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks)
1566 { 2020 {
1567 lock (client.CloseSyncLock) 2021 lock (client.CloseSyncLock)
1568 { 2022 {
2023 ClientLogoutsDueToNoReceives++;
2024
1569 m_log.WarnFormat( 2025 m_log.WarnFormat(
1570 "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", 2026 "[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); 2027 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, m_scene.Name);
1572
1573 StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
1574 2028
1575 if (!client.SceneAgent.IsChildAgent) 2029 if (!client.SceneAgent.IsChildAgent)
1576 client.Kick("Simulator logged you out due to connection timeout"); 2030 client.Kick("Simulator logged you out due to connection timeout.");
1577
1578 client.CloseWithoutChecks(true);
1579 } 2031 }
2032
2033 m_scene.CloseAgent(client.AgentId, true);
1580 } 2034 }
1581 2035
1582 private void IncomingPacketHandler() 2036 private void IncomingPacketHandler()
@@ -1592,6 +2046,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1592 { 2046 {
1593 IncomingPacket incomingPacket = null; 2047 IncomingPacket incomingPacket = null;
1594 2048
2049 /*
1595 // HACK: This is a test to try and rate limit packet handling on Mono. 2050 // 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 2051 // If it works, a more elegant solution can be devised
1597 if (Util.FireAndForgetCount() < 2) 2052 if (Util.FireAndForgetCount() < 2)
@@ -1599,6 +2054,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1599 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); 2054 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping");
1600 Thread.Sleep(30); 2055 Thread.Sleep(30);
1601 } 2056 }
2057 */
1602 2058
1603 if (packetInbox.Dequeue(100, ref incomingPacket)) 2059 if (packetInbox.Dequeue(100, ref incomingPacket))
1604 { 2060 {
@@ -1694,8 +2150,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1694 2150
1695 // If nothing was sent, sleep for the minimum amount of time before a 2151 // If nothing was sent, sleep for the minimum amount of time before a
1696 // token bucket could get more tokens 2152 // token bucket could get more tokens
2153 //if (!m_packetSent)
2154 // Thread.Sleep((int)TickCountResolution);
2155 //
2156 // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with
2157 // modern mono it reduces CPU base load since there is no more continuous polling.
1697 if (!m_packetSent) 2158 if (!m_packetSent)
1698 Thread.Sleep((int)TickCountResolution); 2159 m_dataPresentEvent.WaitOne(100);
1699 2160
1700 Watchdog.UpdateThread(); 2161 Watchdog.UpdateThread();
1701 } 2162 }
@@ -1912,7 +2373,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1912 if (!client.IsLoggingOut) 2373 if (!client.IsLoggingOut)
1913 { 2374 {
1914 client.IsLoggingOut = true; 2375 client.IsLoggingOut = true;
1915 client.Close(false, false); 2376 m_scene.CloseAgent(client.AgentId, false);
1916 } 2377 }
1917 } 2378 }
1918 } 2379 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index 7035e38..881e768 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -78,6 +78,36 @@ namespace OpenMetaverse
78 public bool IsRunningOutbound { get; private set; } 78 public bool IsRunningOutbound { get; private set; }
79 79
80 /// <summary> 80 /// <summary>
81 /// Number of UDP receives.
82 /// </summary>
83 public int UdpReceives { get; private set; }
84
85 /// <summary>
86 /// Number of UDP sends
87 /// </summary>
88 public int UdpSends { get; private set; }
89
90 /// <summary>
91 /// Number of receives over which to establish a receive time average.
92 /// </summary>
93 private readonly static int s_receiveTimeSamples = 500;
94
95 /// <summary>
96 /// Current number of samples taken to establish a receive time average.
97 /// </summary>
98 private int m_currentReceiveTimeSamples;
99
100 /// <summary>
101 /// Cumulative receive time for the sample so far.
102 /// </summary>
103 private int m_receiveTicksInCurrentSamplePeriod;
104
105 /// <summary>
106 /// The average time taken for each require receive in the last sample.
107 /// </summary>
108 public float AverageReceiveTicksForLastSamplePeriod { get; private set; }
109
110 /// <summary>
81 /// Default constructor 111 /// Default constructor
82 /// </summary> 112 /// </summary>
83 /// <param name="bindAddress">Local IP address to bind the server to</param> 113 /// <param name="bindAddress">Local IP address to bind the server to</param>
@@ -111,6 +141,8 @@ namespace OpenMetaverse
111 141
112 if (!IsRunningInbound) 142 if (!IsRunningInbound)
113 { 143 {
144 m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop");
145
114 const int SIO_UDP_CONNRESET = -1744830452; 146 const int SIO_UDP_CONNRESET = -1744830452;
115 147
116 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); 148 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
@@ -151,6 +183,8 @@ namespace OpenMetaverse
151 /// </summary> 183 /// </summary>
152 public void StartOutbound() 184 public void StartOutbound()
153 { 185 {
186 m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop");
187
154 IsRunningOutbound = true; 188 IsRunningOutbound = true;
155 } 189 }
156 190
@@ -158,10 +192,8 @@ namespace OpenMetaverse
158 { 192 {
159 if (IsRunningInbound) 193 if (IsRunningInbound)
160 { 194 {
161 // wait indefinitely for a writer lock. Once this is called, the .NET runtime 195 m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop");
162 // will deny any more reader locks, in effect blocking all other send/receive 196
163 // threads. Once we have the lock, we set IsRunningInbound = false to inform the other
164 // threads that the socket is closed.
165 IsRunningInbound = false; 197 IsRunningInbound = false;
166 m_udpSocket.Close(); 198 m_udpSocket.Close();
167 } 199 }
@@ -169,6 +201,8 @@ namespace OpenMetaverse
169 201
170 public void StopOutbound() 202 public void StopOutbound()
171 { 203 {
204 m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop");
205
172 IsRunningOutbound = false; 206 IsRunningOutbound = false;
173 } 207 }
174 208
@@ -257,7 +291,16 @@ namespace OpenMetaverse
257 m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); 291 m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort);
258 } 292 }
259 } 293 }
260 catch (ObjectDisposedException) { } 294 catch (ObjectDisposedException e)
295 {
296 m_log.Error(
297 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
298 }
299 catch (Exception e)
300 {
301 m_log.Error(
302 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
303 }
261 } 304 }
262 } 305 }
263 306
@@ -267,17 +310,21 @@ namespace OpenMetaverse
267 // to AsyncBeginReceive 310 // to AsyncBeginReceive
268 if (IsRunningInbound) 311 if (IsRunningInbound)
269 { 312 {
313 UdpReceives++;
314
270 // Asynchronous mode will start another receive before the 315 // Asynchronous mode will start another receive before the
271 // callback for this packet is even fired. Very parallel :-) 316 // callback for this packet is even fired. Very parallel :-)
272 if (m_asyncPacketHandling) 317 if (m_asyncPacketHandling)
273 AsyncBeginReceive(); 318 AsyncBeginReceive();
274 319
275 // get the buffer that was created in AsyncBeginReceive
276 // this is the received data
277 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
278
279 try 320 try
280 { 321 {
322 // get the buffer that was created in AsyncBeginReceive
323 // this is the received data
324 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
325
326 int startTick = Util.EnvironmentTickCount();
327
281 // get the length of data actually read from the socket, store it with the 328 // get the length of data actually read from the socket, store it with the
282 // buffer 329 // buffer
283 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); 330 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
@@ -285,9 +332,42 @@ namespace OpenMetaverse
285 // call the abstract method PacketReceived(), passing the buffer that 332 // call the abstract method PacketReceived(), passing the buffer that
286 // has just been filled from the socket read. 333 // has just been filled from the socket read.
287 PacketReceived(buffer); 334 PacketReceived(buffer);
335
336 // If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler)
337 // then a particular stat may be inaccurate due to a race condition. We won't worry about this
338 // since this should be rare and won't cause a runtime problem.
339 if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
340 {
341 AverageReceiveTicksForLastSamplePeriod
342 = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
343
344 m_receiveTicksInCurrentSamplePeriod = 0;
345 m_currentReceiveTimeSamples = 0;
346 }
347 else
348 {
349 m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick);
350 m_currentReceiveTimeSamples++;
351 }
352 }
353 catch (SocketException se)
354 {
355 m_log.Error(
356 string.Format(
357 "[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}. Exception ",
358 UdpReceives, se.ErrorCode),
359 se);
360 }
361 catch (ObjectDisposedException e)
362 {
363 m_log.Error(
364 string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
365 }
366 catch (Exception e)
367 {
368 m_log.Error(
369 string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
288 } 370 }
289 catch (SocketException) { }
290 catch (ObjectDisposedException) { }
291 finally 371 finally
292 { 372 {
293// if (UsePools) 373// if (UsePools)
@@ -298,14 +378,13 @@ namespace OpenMetaverse
298 if (!m_asyncPacketHandling) 378 if (!m_asyncPacketHandling)
299 AsyncBeginReceive(); 379 AsyncBeginReceive();
300 } 380 }
301
302 } 381 }
303 } 382 }
304 383
305 public void AsyncBeginSend(UDPPacketBuffer buf) 384 public void AsyncBeginSend(UDPPacketBuffer buf)
306 { 385 {
307 if (IsRunningOutbound) 386// if (IsRunningOutbound)
308 { 387// {
309 try 388 try
310 { 389 {
311 m_udpSocket.BeginSendTo( 390 m_udpSocket.BeginSendTo(
@@ -319,7 +398,7 @@ namespace OpenMetaverse
319 } 398 }
320 catch (SocketException) { } 399 catch (SocketException) { }
321 catch (ObjectDisposedException) { } 400 catch (ObjectDisposedException) { }
322 } 401// }
323 } 402 }
324 403
325 void AsyncEndSend(IAsyncResult result) 404 void AsyncEndSend(IAsyncResult result)
@@ -328,6 +407,8 @@ namespace OpenMetaverse
328 { 407 {
329// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; 408// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
330 m_udpSocket.EndSendTo(result); 409 m_udpSocket.EndSendTo(result);
410
411 UdpSends++;
331 } 412 }
332 catch (SocketException) { } 413 catch (SocketException) { }
333 catch (ObjectDisposedException) { } 414 catch (ObjectDisposedException) { }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
index 1fdc410..5a2bcee 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -145,39 +145,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
145 return packet; 145 return packet;
146 } 146 }
147 147
148 // private byte[] decoded_header = new byte[10];
149 private static PacketType GetType(byte[] bytes) 148 private static PacketType GetType(byte[] bytes)
150 { 149 {
151 byte[] decoded_header = new byte[10 + 8];
152 ushort id; 150 ushort id;
153 PacketFrequency freq; 151 PacketFrequency freq;
152 bool isZeroCoded = (bytes[0] & Helpers.MSG_ZEROCODED) != 0;
154 153
155 if ((bytes[0] & Helpers.MSG_ZEROCODED) != 0) 154 if (bytes[6] == 0xFF)
156 { 155 {
157 Helpers.ZeroDecode(bytes, 16, decoded_header); 156 if (bytes[7] == 0xFF)
158 }
159 else
160 {
161 Buffer.BlockCopy(bytes, 0, decoded_header, 0, 10);
162 }
163
164 if (decoded_header[6] == 0xFF)
165 {
166 if (decoded_header[7] == 0xFF)
167 { 157 {
168 id = (ushort) ((decoded_header[8] << 8) + decoded_header[9]);
169 freq = PacketFrequency.Low; 158 freq = PacketFrequency.Low;
159 if (isZeroCoded && bytes[8] == 0)
160 id = bytes[10];
161 else
162 id = (ushort)((bytes[8] << 8) + bytes[9]);
170 } 163 }
171 else 164 else
172 { 165 {
173 id = decoded_header[7];
174 freq = PacketFrequency.Medium; 166 freq = PacketFrequency.Medium;
167 id = bytes[7];
175 } 168 }
176 } 169 }
177 else 170 else
178 { 171 {
179 id = decoded_header[6];
180 freq = PacketFrequency.High; 172 freq = PacketFrequency.High;
173 id = bytes[6];
181 } 174 }
182 175
183 return Packet.GetType(id, freq); 176 return Packet.GetType(id, freq);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
index 98ef72f..f8d0c02 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.6.*")] 32[assembly: AssemblyVersion("0.8.0.*")]
33 33
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
index 556df30..9700224 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
@@ -33,6 +33,7 @@ using NUnit.Framework;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenMetaverse.Packets; 34using OpenMetaverse.Packets;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
37using OpenSim.Tests.Common; 38using OpenSim.Tests.Common;
38using OpenSim.Tests.Common.Mock; 39using OpenSim.Tests.Common.Mock;
@@ -69,6 +70,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
69 { 70 {
70 base.SetUp(); 71 base.SetUp();
71 m_scene = new SceneHelpers().SetupScene(); 72 m_scene = new SceneHelpers().SetupScene();
73 StatsManager.SimExtraStats = new SimExtraStatsCollector();
72 } 74 }
73 75
74 /// <summary> 76 /// <summary>
@@ -198,7 +200,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
198 public void TestLogoutClientDueToAck() 200 public void TestLogoutClientDueToAck()
199 { 201 {
200 TestHelpers.InMethod(); 202 TestHelpers.InMethod();
201// TestHelpers.EnableLogging(); 203 TestHelpers.EnableLogging();
202 204
203 IniConfigSource ics = new IniConfigSource(); 205 IniConfigSource ics = new IniConfigSource();
204 IConfig config = ics.AddConfig("ClientStack.LindenUDP"); 206 IConfig config = ics.AddConfig("ClientStack.LindenUDP");
@@ -210,8 +212,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
210 212
211 ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); 213 ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID);
212 Assert.That(spAfterAckTimeout, Is.Null); 214 Assert.That(spAfterAckTimeout, Is.Null);
213
214// TestHelpers.DisableLogging();
215 } 215 }
216 216
217// /// <summary> 217// /// <summary>
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
index 7d9f581..575e54c 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
@@ -29,6 +29,7 @@ using System;
29using System.IO; 29using System.IO;
30using System.Net; 30using System.Net;
31using System.Reflection; 31using System.Reflection;
32using System.Threading;
32using log4net.Config; 33using log4net.Config;
33using Nini.Config; 34using Nini.Config;
34using NUnit.Framework; 35using NUnit.Framework;
@@ -53,6 +54,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
53 [TestFixtureSetUp] 54 [TestFixtureSetUp]
54 public void FixtureInit() 55 public void FixtureInit()
55 { 56 {
57 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
58 Util.FireAndForgetMethod = FireAndForgetMethod.None;
59
56 using ( 60 using (
57 Stream resource 61 Stream resource
58 = GetType().Assembly.GetManifestResourceStream( 62 = GetType().Assembly.GetManifestResourceStream(
@@ -72,9 +76,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
72 } 76 }
73 } 77 }
74 78
79 [TestFixtureTearDown]
80 public void TearDown()
81 {
82 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
83 // threads. Possibly, later tests should be rewritten not to worry about such things.
84 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
85 }
86
75 [SetUp] 87 [SetUp]
76 public void SetUp() 88 public override void SetUp()
77 { 89 {
90 base.SetUp();
91
78 UUID userId = TestHelpers.ParseTail(0x3); 92 UUID userId = TestHelpers.ParseTail(0x3);
79 93
80 J2KDecoderModule j2kdm = new J2KDecoderModule(); 94 J2KDecoderModule j2kdm = new J2KDecoderModule();
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
index 119a677..e2178e5 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
@@ -52,17 +52,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
52 public override void Update(int frames) {} 52 public override void Update(int frames) {}
53 public override void LoadWorldMap() {} 53 public override void LoadWorldMap() {}
54 54
55 public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type) 55 public override ISceneAgent AddNewAgent(IClientAPI client, PresenceType type)
56 { 56 {
57 client.OnObjectName += RecordObjectNameCall; 57 client.OnObjectName += RecordObjectNameCall;
58 58
59 // FIXME 59 // FIXME
60 return null; 60 return null;
61 } 61 }
62 62
63 public override void RemoveClient(UUID agentID, bool someReason) {} 63 public override bool CloseAgent(UUID agentID, bool force) { return true; }
64// public override void CloseAllAgents(uint circuitcode) {} 64
65 public override bool CheckClient(UUID clientId, IPEndPoint endPoint) { return true; } 65 public override bool CheckClient(UUID clientId, IPEndPoint endPoint) { return true; }
66
66 public override void OtherRegionUp(GridRegion otherRegion) { } 67 public override void OtherRegionUp(GridRegion otherRegion) { }
67 68
68 public override bool TryGetScenePresence(UUID uuid, out ScenePresence sp) { sp = null; return false; } 69 public override bool TryGetScenePresence(UUID uuid, out ScenePresence sp) { sp = null; return false; }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
index c9aac0b..e5bae6e 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
@@ -59,6 +59,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
59 /// <summary>Flag used to enable adaptive throttles</summary> 59 /// <summary>Flag used to enable adaptive throttles</summary>
60 public bool AdaptiveThrottlesEnabled; 60 public bool AdaptiveThrottlesEnabled;
61 61
62 /// <summary>Amount of the texture throttle to steal for the task throttle</summary>
63 public double CannibalizeTextureRate;
64
62 /// <summary> 65 /// <summary>
63 /// Default constructor 66 /// Default constructor
64 /// </summary> 67 /// </summary>
@@ -80,6 +83,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
80 Total = throttleConfig.GetInt("client_throttle_max_bps", 0); 83 Total = throttleConfig.GetInt("client_throttle_max_bps", 0);
81 84
82 AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); 85 AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false);
86
87 CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f);
88 CannibalizeTextureRate = Util.Clamp<double>(CannibalizeTextureRate,0.0, 0.9);
83 } 89 }
84 catch (Exception) { } 90 catch (Exception) { }
85 } 91 }