aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/IClientNetworkServer.cs15
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs136
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs57
-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.cs1079
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs7
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs126
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs684
-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, 2069 insertions, 1218 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..61b9045 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -248,7 +248,19 @@ namespace OpenSim.Region.ClientStack.Linden
248 //m_capsHandlers["MapLayer"] = 248 //m_capsHandlers["MapLayer"] =
249 // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST", 249 // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST",
250 // capsBase + m_mapLayerPath, 250 // capsBase + m_mapLayerPath,
251 // GetMapLayer); 251 // GetMapLayer);
252
253 IRequestHandler getObjectPhysicsDataHandler
254 = new RestStreamHandler(
255 "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null);
256 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
257
258 IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost);
259 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler);
260 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected);
261 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler);
262
263
252 IRequestHandler req 264 IRequestHandler req
253 = new RestStreamHandler( 265 = new RestStreamHandler(
254 "POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory, "UpdateScript", null); 266 "POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory, "UpdateScript", null);
@@ -282,13 +294,12 @@ namespace OpenSim.Region.ClientStack.Linden
282 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); 294 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
283 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); 295 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
284 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); 296 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
285 IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData); 297
286 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); 298
287 IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost); 299
288 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler); 300 IRequestHandler UpdateAgentInformationHandler
289 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected); 301 = new RestStreamHandler(
290 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler); 302 "POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation, "UpdateAgentInformation", null);
291 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation);
292 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); 303 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler);
293 304
294 m_HostCapsObj.RegisterHandler( 305 m_HostCapsObj.RegisterHandler(
@@ -361,18 +372,7 @@ namespace OpenSim.Region.ClientStack.Linden
361 foreach (OSD c in capsRequested) 372 foreach (OSD c in capsRequested)
362 validCaps.Add(c.AsString()); 373 validCaps.Add(c.AsString());
363 374
364 Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true, validCaps); 375 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 376
377 //m_log.DebugFormat("[CAPS] CapsRequest {0}", result); 377 //m_log.DebugFormat("[CAPS] CapsRequest {0}", result);
378 378
@@ -748,6 +748,10 @@ namespace OpenSim.Region.ClientStack.Linden
748 inType = (sbyte)InventoryType.Sound; 748 inType = (sbyte)InventoryType.Sound;
749 assType = (sbyte)AssetType.Sound; 749 assType = (sbyte)AssetType.Sound;
750 } 750 }
751 else if (inventoryType == "snapshot")
752 {
753 inType = (sbyte)InventoryType.Snapshot;
754 }
751 else if (inventoryType == "animation") 755 else if (inventoryType == "animation")
752 { 756 {
753 inType = (sbyte)InventoryType.Animation; 757 inType = (sbyte)InventoryType.Animation;
@@ -1380,6 +1384,17 @@ namespace OpenSim.Region.ClientStack.Linden
1380 1384
1381 resp[uuid.ToString()] = object_data; 1385 resp[uuid.ToString()] = object_data;
1382 } 1386 }
1387 else
1388 {
1389 OSDMap object_data = new OSDMap();
1390 object_data["linked_set_resource_cost"] = 0;
1391 object_data["resource_cost"] = 0;
1392 object_data["physics_cost"] = 0;
1393 object_data["linked_set_physics_cost"] = 0;
1394
1395 resp[uuid.ToString()] = object_data;
1396 }
1397
1383 } 1398 }
1384 } 1399 }
1385 1400
@@ -1444,7 +1459,7 @@ namespace OpenSim.Region.ClientStack.Linden
1444 } 1459 }
1445 } 1460 }
1446 1461
1447 if (simul != 0) 1462 // if (simul != 0)
1448 { 1463 {
1449 OSDMap object_data = new OSDMap(); 1464 OSDMap object_data = new OSDMap();
1450 1465
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..06f1301 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
@@ -355,7 +358,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
355// protected HashSet<uint> m_attachmentsSent; 358// protected HashSet<uint> m_attachmentsSent;
356 359
357 private bool m_deliverPackets = true; 360 private bool m_deliverPackets = true;
358 private int m_animationSequenceNumber = 1; 361
359 private bool m_SendLogoutPacketWhenClosing = true; 362 private bool m_SendLogoutPacketWhenClosing = true;
360 363
361 /// <summary> 364 /// <summary>
@@ -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
@@ -416,6 +419,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
416 public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } } 419 public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } }
417 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); } 420 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); }
418 421
422 public int PingTimeMS
423 {
424 get
425 {
426 if (UDPClient != null)
427 return UDPClient.PingTimeMS;
428 return 0;
429 }
430 }
431
419 /// <summary> 432 /// <summary>
420 /// Entity update queues 433 /// Entity update queues
421 /// </summary> 434 /// </summary>
@@ -437,7 +450,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
437 public string Name { get { return FirstName + " " + LastName; } } 450 public string Name { get { return FirstName + " " + LastName; } }
438 451
439 public uint CircuitCode { get { return m_circuitCode; } } 452 public uint CircuitCode { get { return m_circuitCode; } }
440 public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } } 453 public int NextAnimationSequenceNumber
454 {
455 get { return m_udpServer.NextAnimationSequenceNumber; }
456 }
441 457
442 /// <summary> 458 /// <summary>
443 /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to 459 /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to
@@ -458,6 +474,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
458 set { m_disableFacelights = value; } 474 set { m_disableFacelights = value; }
459 } 475 }
460 476
477
461 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } 478 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } }
462 479
463 480
@@ -504,6 +521,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
504 m_udpServer = udpServer; 521 m_udpServer = udpServer;
505 m_udpClient = udpClient; 522 m_udpClient = udpClient;
506 m_udpClient.OnQueueEmpty += HandleQueueEmpty; 523 m_udpClient.OnQueueEmpty += HandleQueueEmpty;
524 m_udpClient.HasUpdates += HandleHasUpdates;
507 m_udpClient.OnPacketStats += PopulateStats; 525 m_udpClient.OnPacketStats += PopulateStats;
508 526
509 m_prioritizer = new Prioritizer(m_scene); 527 m_prioritizer = new Prioritizer(m_scene);
@@ -533,7 +551,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 551 // 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 552 // there is some unidentified connection problem, not where we have issues due to deadlock
535 if (!IsActive && !force) 553 if (!IsActive && !force)
554 {
555 m_log.DebugFormat(
556 "[CLIENT]: Not attempting to close inactive client {0} in {1} since force flag is not set",
557 Name, m_scene.Name);
558
536 return; 559 return;
560 }
537 561
538 IsActive = false; 562 IsActive = false;
539 CloseWithoutChecks(sendStop); 563 CloseWithoutChecks(sendStop);
@@ -709,12 +733,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
709 //there is a local handler for this packet type 733 //there is a local handler for this packet type
710 if (pprocessor.Async) 734 if (pprocessor.Async)
711 { 735 {
736 ClientInfo cinfo = UDPClient.GetClientInfo();
737 if (!cinfo.AsyncRequests.ContainsKey(packet.Type.ToString()))
738 cinfo.AsyncRequests[packet.Type.ToString()] = 0;
739 cinfo.AsyncRequests[packet.Type.ToString()]++;
740
712 object obj = new AsyncPacketProcess(this, pprocessor.method, packet); 741 object obj = new AsyncPacketProcess(this, pprocessor.method, packet);
713 Util.FireAndForget(ProcessSpecificPacketAsync, obj); 742 Util.FireAndForget(ProcessSpecificPacketAsync, obj);
714 result = true; 743 result = true;
715 } 744 }
716 else 745 else
717 { 746 {
747 ClientInfo cinfo = UDPClient.GetClientInfo();
748 if (!cinfo.SyncRequests.ContainsKey(packet.Type.ToString()))
749 cinfo.SyncRequests[packet.Type.ToString()] = 0;
750 cinfo.SyncRequests[packet.Type.ToString()]++;
751
718 result = pprocessor.method(this, packet); 752 result = pprocessor.method(this, packet);
719 } 753 }
720 } 754 }
@@ -729,6 +763,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
729 } 763 }
730 if (found) 764 if (found)
731 { 765 {
766 ClientInfo cinfo = UDPClient.GetClientInfo();
767 if (!cinfo.GenericRequests.ContainsKey(packet.Type.ToString()))
768 cinfo.GenericRequests[packet.Type.ToString()] = 0;
769 cinfo.GenericRequests[packet.Type.ToString()]++;
770
732 result = method(this, packet); 771 result = method(this, packet);
733 } 772 }
734 } 773 }
@@ -758,7 +797,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
758 797
759 public virtual void Start() 798 public virtual void Start()
760 { 799 {
761 m_scene.AddNewClient(this, PresenceType.User); 800 m_scene.AddNewAgent(this, PresenceType.User);
762 801
763 RefreshGroupMembership(); 802 RefreshGroupMembership();
764 } 803 }
@@ -820,14 +859,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
820 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); 859 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType);
821 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; 860 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes;
822 861
823 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0]; 862 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1];
824// OutPacket(handshake, ThrottleOutPacketType.Task); 863 handshake.RegionInfo4[0] = new RegionHandshakePacket.RegionInfo4Block();
825 // use same as MoveAgentIntoRegion (both should be task ) 864 handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags;
865 handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported
866
826 OutPacket(handshake, ThrottleOutPacketType.Unknown); 867 OutPacket(handshake, ThrottleOutPacketType.Unknown);
827 } 868 }
828 869
870
829 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) 871 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
830 { 872 {
873 m_thisAgentUpdateArgs.CameraAtAxis.X = float.MinValue;
874 m_thisAgentUpdateArgs.ControlFlags = uint.MaxValue;
875
831 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); 876 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete);
832 mov.SimData.ChannelVersion = m_channelVersion; 877 mov.SimData.ChannelVersion = m_channelVersion;
833 mov.AgentData.SessionID = m_sessionId; 878 mov.AgentData.SessionID = m_sessionId;
@@ -1210,9 +1255,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1210 LLHeightFieldMoronize(map); 1255 LLHeightFieldMoronize(map);
1211 1256
1212 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1257 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1213 layerpack.Header.Reliable = true; 1258
1259 // When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience.
1260 // To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain.
1261 // We also make them unreliable because it's extremely likely that multiple packets will be sent for a terrain patch area
1262 // invalidating previous packets for that area.
1214 1263
1215 OutPacket(layerpack, ThrottleOutPacketType.Task); 1264 // It's possible for an editing user to flood themselves with edited packets but the majority of use cases are such that only a
1265 // tiny percentage of users will be editing the terrain. Other, non-editing users will see the edits much slower.
1266
1267 // 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
1268 // have rezzed already and therefore this is not likely going to cause any additional issues with lost packets, objects or terrain
1269 // patches.
1270
1271 // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we only have one cache miss.
1272 if (m_justEditedTerrain)
1273 {
1274 layerpack.Header.Reliable = false;
1275 OutPacket(layerpack,
1276 ThrottleOutPacketType.Unknown );
1277 }
1278 else
1279 {
1280 layerpack.Header.Reliable = true;
1281 OutPacket(layerpack,
1282 ThrottleOutPacketType.Task);
1283 }
1216 } 1284 }
1217 catch (Exception e) 1285 catch (Exception e)
1218 { 1286 {
@@ -1405,6 +1473,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1405 1473
1406 mapReply.AgentData.AgentID = AgentId; 1474 mapReply.AgentData.AgentID = AgentId;
1407 mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length]; 1475 mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length];
1476 mapReply.Size = new MapBlockReplyPacket.SizeBlock[mapBlocks2.Length];
1408 mapReply.AgentData.Flags = flag; 1477 mapReply.AgentData.Flags = flag;
1409 1478
1410 for (int i = 0; i < mapBlocks2.Length; i++) 1479 for (int i = 0; i < mapBlocks2.Length; i++)
@@ -1419,6 +1488,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1419 mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags; 1488 mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags;
1420 mapReply.Data[i].Access = mapBlocks2[i].Access; 1489 mapReply.Data[i].Access = mapBlocks2[i].Access;
1421 mapReply.Data[i].Agents = mapBlocks2[i].Agents; 1490 mapReply.Data[i].Agents = mapBlocks2[i].Agents;
1491
1492 // TODO: hookup varregion sim size here
1493 mapReply.Size[i] = new MapBlockReplyPacket.SizeBlock();
1494 mapReply.Size[i].SizeX = 256;
1495 mapReply.Size[i].SizeY = 256;
1422 } 1496 }
1423 OutPacket(mapReply, ThrottleOutPacketType.Land); 1497 OutPacket(mapReply, ThrottleOutPacketType.Land);
1424 } 1498 }
@@ -1578,9 +1652,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1578 pc.PingID.OldestUnacked = 0; 1652 pc.PingID.OldestUnacked = 0;
1579 1653
1580 OutPacket(pc, ThrottleOutPacketType.Unknown); 1654 OutPacket(pc, ThrottleOutPacketType.Unknown);
1655 UDPClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount();
1581 } 1656 }
1582 1657
1583 public void SendKillObject(ulong regionHandle, List<uint> localIDs) 1658 public void SendKillObject(List<uint> localIDs)
1584 { 1659 {
1585// foreach (uint id in localIDs) 1660// foreach (uint id in localIDs)
1586// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); 1661// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
@@ -2594,11 +2669,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2594 { 2669 {
2595 AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket(); 2670 AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket();
2596 avatarSitResponse.SitObject.ID = TargetID; 2671 avatarSitResponse.SitObject.ID = TargetID;
2597 if (CameraAtOffset != Vector3.Zero) 2672 avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset;
2598 { 2673 avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset;
2599 avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset;
2600 avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset;
2601 }
2602 avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook; 2674 avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook;
2603 avatarSitResponse.SitTransform.AutoPilot = autopilot; 2675 avatarSitResponse.SitTransform.AutoPilot = autopilot;
2604 avatarSitResponse.SitTransform.SitPosition = OffsetPos; 2676 avatarSitResponse.SitTransform.SitPosition = OffsetPos;
@@ -3630,6 +3702,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3630 avp.Sender.IsTrial = false; 3702 avp.Sender.IsTrial = false;
3631 avp.Sender.ID = agentID; 3703 avp.Sender.ID = agentID;
3632 avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0]; 3704 avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0];
3705
3706 // this need be use in future
3707 // avp.AppearanceData[0].AppearanceVersion = 0;
3708 // avp.AppearanceData[0].CofVersion = 0;
3709
3633 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); 3710 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString());
3634 OutPacket(avp, ThrottleOutPacketType.Task); 3711 OutPacket(avp, ThrottleOutPacketType.Task);
3635 } 3712 }
@@ -3751,8 +3828,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3751 { 3828 {
3752 SceneObjectPart e = (SceneObjectPart)entity; 3829 SceneObjectPart e = (SceneObjectPart)entity;
3753 SceneObjectGroup g = e.ParentGroup; 3830 SceneObjectGroup g = e.ParentGroup;
3754 if (g.RootPart.Shape.State > 30) // HUD 3831 if (g.HasPrivateAttachmentPoint && g.OwnerID != AgentId)
3755 if (g.OwnerID != AgentId)
3756 return; // Don't send updates for other people's HUDs 3832 return; // Don't send updates for other people's HUDs
3757 } 3833 }
3758 3834
@@ -3762,43 +3838,64 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3762 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); 3838 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation));
3763 } 3839 }
3764 3840
3765 /// <summary> 3841 /* dont use this
3766 /// Requeue an EntityUpdate when it was not acknowledged by the client. 3842 udp packet resent must be done at udp level only
3767 /// We will update the priority and put it in the correct queue, merging update flags 3843 re map from a packet to original updates just doesnt work
3768 /// with any other updates that may be queued for the same entity.
3769 /// The original update time is used for the merged update.
3770 /// </summary>
3771 private void ResendPrimUpdate(EntityUpdate update)
3772 {
3773 // If the update exists in priority queue, it will be updated.
3774 // If it does not exist then it will be added with the current (rather than its original) priority
3775 uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity);
3776 3844
3777 lock (m_entityUpdates.SyncRoot) 3845 /// <summary>
3778 m_entityUpdates.Enqueue(priority, update); 3846 /// Requeue an EntityUpdate when it was not acknowledged by the client.
3779 } 3847 /// We will update the priority and put it in the correct queue, merging update flags
3848 /// with any other updates that may be queued for the same entity.
3849 /// The original update time is used for the merged update.
3850 /// </summary>
3851 private void ResendPrimUpdate(EntityUpdate update)
3852 {
3853 // If the update exists in priority queue, it will be updated.
3854 // If it does not exist then it will be added with the current (rather than its original) priority
3855 uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity);
3780 3856
3781 /// <summary> 3857 lock (m_entityUpdates.SyncRoot)
3782 /// Requeue a list of EntityUpdates when they were not acknowledged by the client. 3858 m_entityUpdates.Enqueue(priority, update);
3783 /// We will update the priority and put it in the correct queue, merging update flags 3859 }
3784 /// with any other updates that may be queued for the same entity.
3785 /// The original update time is used for the merged update.
3786 /// </summary>
3787 private void ResendPrimUpdates(List<EntityUpdate> updates, OutgoingPacket oPacket)
3788 {
3789 // m_log.WarnFormat("[CLIENT] resending prim updates {0}, packet sequence number {1}", updates[0].UpdateTime, oPacket.SequenceNumber);
3790 3860
3791 // Remove the update packet from the list of packets waiting for acknowledgement
3792 // because we are requeuing the list of updates. They will be resent in new packets
3793 // with the most recent state and priority.
3794 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
3795 3861
3796 // Count this as a resent packet since we are going to requeue all of the updates contained in it 3862 /// <summary>
3797 Interlocked.Increment(ref m_udpClient.PacketsResent); 3863 /// Requeue a list of EntityUpdates when they were not acknowledged by the client.
3864 /// We will update the priority and put it in the correct queue, merging update flags
3865 /// with any other updates that may be queued for the same entity.
3866 /// The original update time is used for the merged update.
3867 /// </summary>
3868 private void ResendPrimUpdates(List<EntityUpdate> updates, OutgoingPacket oPacket)
3869 {
3870 // m_log.WarnFormat("[CLIENT] resending prim updates {0}, packet sequence number {1}", updates[0].UpdateTime, oPacket.SequenceNumber);
3871
3872 // Remove the update packet from the list of packets waiting for acknowledgement
3873 // because we are requeuing the list of updates. They will be resent in new packets
3874 // with the most recent state and priority.
3875 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
3876
3877 // Count this as a resent packet since we are going to requeue all of the updates contained in it
3878 Interlocked.Increment(ref m_udpClient.PacketsResent);
3879
3880 // We're not going to worry about interlock yet since its not currently critical that this total count
3881 // is 100% correct
3882 m_udpServer.PacketsResentCount++;
3883
3884 foreach (EntityUpdate update in updates)
3885 ResendPrimUpdate(update);
3886 }
3887 */
3888
3889// OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
3890// OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>();
3891// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3892// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3893//
3894// OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3895// OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3896// OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3897// OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3798 3898
3799 foreach (EntityUpdate update in updates)
3800 ResendPrimUpdate(update);
3801 }
3802 3899
3803 private void ProcessEntityUpdates(int maxUpdates) 3900 private void ProcessEntityUpdates(int maxUpdates)
3804 { 3901 {
@@ -3812,6 +3909,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3812 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); 3909 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>>(); 3910 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3814 3911
3912// objectUpdateBlocks.Value.Clear();
3913// compressedUpdateBlocks.Value.Clear();
3914// terseUpdateBlocks.Value.Clear();
3915// terseAgentUpdateBlocks.Value.Clear();
3916// objectUpdates.Value.Clear();
3917// compressedUpdates.Value.Clear();
3918// terseUpdates.Value.Clear();
3919// terseAgentUpdates.Value.Clear();
3920
3815 // Check to see if this is a flush 3921 // Check to see if this is a flush
3816 if (maxUpdates <= 0) 3922 if (maxUpdates <= 0)
3817 { 3923 {
@@ -3846,8 +3952,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3846 3952
3847 if (part.ParentGroup.IsAttachment) 3953 if (part.ParentGroup.IsAttachment)
3848 { // Someone else's HUD, why are we getting these? 3954 { // Someone else's HUD, why are we getting these?
3849 if (part.ParentGroup.OwnerID != AgentId && 3955 if (part.ParentGroup.OwnerID != AgentId && part.ParentGroup.HasPrivateAttachmentPoint)
3850 part.ParentGroup.RootPart.Shape.State > 30)
3851 continue; 3956 continue;
3852 ScenePresence sp; 3957 ScenePresence sp;
3853 // Owner is not in the sim, don't update it to 3958 // Owner is not in the sim, don't update it to
@@ -4098,12 +4203,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4098 for (int i = 0; i < blocks.Count; i++) 4203 for (int i = 0; i < blocks.Count; i++)
4099 packet.ObjectData[i] = blocks[i]; 4204 packet.ObjectData[i] = blocks[i];
4100 4205
4101 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); 4206// OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4207 // use default udp retry
4208 OutPacket(packet, ThrottleOutPacketType.Task, true);
4102 } 4209 }
4103 4210
4211
4212
4104 #endregion Packet Sending 4213 #endregion Packet Sending
4214
4105 } 4215 }
4106 4216
4217 // hack.. dont use
4218 public void SendPartFullUpdate(ISceneEntity ent, uint? parentID)
4219 {
4220 if (ent is SceneObjectPart)
4221 {
4222 SceneObjectPart part = (SceneObjectPart)ent;
4223 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4224 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4225 packet.RegionData.TimeDilation = 1;
4226 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
4227
4228 ObjectUpdatePacket.ObjectDataBlock blk = CreatePrimUpdateBlock(part, this.m_agentId);
4229 if (parentID.HasValue)
4230 {
4231 blk.ParentID = parentID.Value;
4232 }
4233
4234 packet.ObjectData[0] = blk;
4235
4236 OutPacket(packet, ThrottleOutPacketType.Task, true);
4237 }
4238 }
4239
4107 public void ReprioritizeUpdates() 4240 public void ReprioritizeUpdates()
4108 { 4241 {
4109 lock (m_entityUpdates.SyncRoot) 4242 lock (m_entityUpdates.SyncRoot)
@@ -4140,8 +4273,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4140 4273
4141 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) 4274 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
4142 { 4275 {
4276// if (!m_udpServer.IsRunningOutbound)
4277// return;
4278
4143 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) 4279 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4144 { 4280 {
4281// if (!m_udpServer.IsRunningOutbound)
4282// return;
4283
4145 if (m_maxUpdates == 0 || m_LastQueueFill == 0) 4284 if (m_maxUpdates == 0 || m_LastQueueFill == 0)
4146 { 4285 {
4147 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; 4286 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
@@ -4167,6 +4306,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4167 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); 4306 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit);
4168 } 4307 }
4169 4308
4309 internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories)
4310 {
4311 bool hasUpdates = false;
4312
4313 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4314 {
4315 if (m_entityUpdates.Count > 0)
4316 hasUpdates = true;
4317 else if (m_entityProps.Count > 0)
4318 hasUpdates = true;
4319 }
4320
4321 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
4322 {
4323 if (ImageManager.HasUpdates())
4324 hasUpdates = true;
4325 }
4326
4327 return hasUpdates;
4328 }
4329
4170 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) 4330 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
4171 { 4331 {
4172 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); 4332 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
@@ -4312,6 +4472,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 4472 // 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); 4473 Interlocked.Increment(ref m_udpClient.PacketsResent);
4314 4474
4475 // We're not going to worry about interlock yet since its not currently critical that this total count
4476 // is 100% correct
4477 m_udpServer.PacketsResentCount++;
4478
4315 foreach (ObjectPropertyUpdate update in updates) 4479 foreach (ObjectPropertyUpdate update in updates)
4316 ResendPropertyUpdate(update); 4480 ResendPropertyUpdate(update);
4317 } 4481 }
@@ -4499,6 +4663,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4499 SceneObjectPart root = sop.ParentGroup.RootPart; 4663 SceneObjectPart root = sop.ParentGroup.RootPart;
4500 4664
4501 block.TouchName = Util.StringToBytes256(root.TouchName); 4665 block.TouchName = Util.StringToBytes256(root.TouchName);
4666
4667 // SL 3.3.4, at least, appears to read this information as a concatenated byte[] stream of UUIDs but
4668 // it's not yet clear whether this is actually used. If this is done in the future then a pre-cached
4669 // copy is really needed since it's less efficient to be constantly recreating this byte array.
4670// using (MemoryStream memStream = new MemoryStream())
4671// {
4672// using (BinaryWriter binWriter = new BinaryWriter(memStream))
4673// {
4674// for (int i = 0; i < sop.GetNumberOfSides(); i++)
4675// {
4676// Primitive.TextureEntryFace teFace = sop.Shape.Textures.FaceTextures[i];
4677//
4678// UUID textureID;
4679//
4680// if (teFace != null)
4681// textureID = teFace.TextureID;
4682// else
4683// textureID = sop.Shape.Textures.DefaultTexture.TextureID;
4684//
4685// binWriter.Write(textureID.GetBytes());
4686// }
4687//
4688// block.TextureID = memStream.ToArray();
4689// }
4690// }
4691
4502 block.TextureID = new byte[0]; // TextureID ??? 4692 block.TextureID = new byte[0]; // TextureID ???
4503 block.SitName = Util.StringToBytes256(root.SitName); 4693 block.SitName = Util.StringToBytes256(root.SitName);
4504 block.OwnerMask = root.OwnerMask; 4694 block.OwnerMask = root.OwnerMask;
@@ -4839,7 +5029,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4839 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); 5029 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
4840 if (eq != null) 5030 if (eq != null)
4841 { 5031 {
4842 eq.ParcelProperties(updateMessage, this.AgentId); 5032 OSD message_body = updateMessage.Serialize();
5033 // Add new fields here until OMV has them
5034 OSDMap bodyMap = (OSDMap)message_body;
5035 OSDArray parcelDataArray = (OSDArray)bodyMap["ParcelData"];
5036 OSDMap parcelData = (OSDMap)parcelDataArray[0];
5037 parcelData["SeeAVs"] = OSD.FromBoolean(landData.SeeAVs);
5038 parcelData["AnyAVSounds"] = OSD.FromBoolean(landData.AnyAVSounds);
5039 parcelData["GroupAVSounds"] = OSD.FromBoolean(landData.GroupAVSounds);
5040 OSDMap message = new OSDMap();
5041 message.Add("message", OSD.FromString("ParcelProperties"));
5042 message.Add("body", message_body);
5043 eq.Enqueue (message, this.AgentId);
5044 //eq.ParcelProperties(updateMessage, this.AgentId);
4843 } 5045 }
4844 else 5046 else
4845 { 5047 {
@@ -4877,7 +5079,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4877 5079
4878 public void SendForceClientSelectObjects(List<uint> ObjectIDs) 5080 public void SendForceClientSelectObjects(List<uint> ObjectIDs)
4879 { 5081 {
4880 m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); 5082// m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count);
4881 5083
4882 bool firstCall = true; 5084 bool firstCall = true;
4883 const int MAX_OBJECTS_PER_PACKET = 251; 5085 const int MAX_OBJECTS_PER_PACKET = 251;
@@ -4997,33 +5199,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4997 5199
4998 position = presence.OffsetPosition; 5200 position = presence.OffsetPosition;
4999 rotation = presence.Rotation; 5201 rotation = presence.Rotation;
5000 5202 angularVelocity = presence.AngularVelocity;
5001 if (presence.ParentID != 0) 5203 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 5204
5017 attachPoint = 0; 5205 attachPoint = 0;
5206// m_log.DebugFormat(
5207// "[LLCLIENTVIEW]: Sending terse update to {0} with position {1} in {2}", Name, presence.OffsetPosition, m_scene.Name);
5208
5209 // attachPoint = presence.State; // Core: commented
5018 collisionPlane = presence.CollisionPlane; 5210 collisionPlane = presence.CollisionPlane;
5019 velocity = presence.Velocity; 5211 velocity = presence.Velocity;
5020 acceleration = Vector3.Zero; 5212 acceleration = Vector3.Zero;
5021 5213
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) 5214 if (sendTexture)
5028 textureEntry = presence.Appearance.Texture.GetBytes(); 5215 textureEntry = presence.Appearance.Texture.GetBytes();
5029 else 5216 else
@@ -5034,7 +5221,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5034 SceneObjectPart part = (SceneObjectPart)entity; 5221 SceneObjectPart part = (SceneObjectPart)entity;
5035 5222
5036 attachPoint = part.ParentGroup.AttachmentPoint; 5223 attachPoint = part.ParentGroup.AttachmentPoint;
5037 5224 attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16));
5038// m_log.DebugFormat( 5225// m_log.DebugFormat(
5039// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", 5226// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}",
5040// attachPoint, part.Name, part.LocalId, Name); 5227// attachPoint, part.Name, part.LocalId, Name);
@@ -5062,7 +5249,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5062 pos += 4; 5249 pos += 4;
5063 5250
5064 // Avatar/CollisionPlane 5251 // Avatar/CollisionPlane
5065 data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ; 5252 data[pos++] = (byte) attachPoint;
5066 if (avatar) 5253 if (avatar)
5067 { 5254 {
5068 data[pos++] = 1; 5255 data[pos++] = 1;
@@ -5132,30 +5319,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5132 Vector3 offsetPosition = data.OffsetPosition; 5319 Vector3 offsetPosition = data.OffsetPosition;
5133 Quaternion rotation = data.Rotation; 5320 Quaternion rotation = data.Rotation;
5134 uint parentID = data.ParentID; 5321 uint parentID = data.ParentID;
5135 5322
5136 if (parentID != 0) 5323// m_log.DebugFormat(
5137 { 5324// "[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 5325
5147 byte[] objectData = new byte[76]; 5326 byte[] objectData = new byte[76];
5148 5327
5149 data.CollisionPlane.ToBytes(objectData, 0);
5150 offsetPosition.ToBytes(objectData, 16);
5151 Vector3 velocity = new Vector3(0, 0, 0); 5328 Vector3 velocity = new Vector3(0, 0, 0);
5152 Vector3 acceleration = new Vector3(0, 0, 0); 5329 Vector3 acceleration = new Vector3(0, 0, 0);
5330 rotation.Normalize();
5331 Vector3 vrot = new Vector3(rotation.X, rotation.Y, rotation.Z);
5332
5333 data.CollisionPlane.ToBytes(objectData, 0);
5334 offsetPosition.ToBytes(objectData, 16);
5153 velocity.ToBytes(objectData, 28); 5335 velocity.ToBytes(objectData, 28);
5154 acceleration.ToBytes(objectData, 40); 5336 acceleration.ToBytes(objectData, 40);
5155// data.Velocity.ToBytes(objectData, 28); 5337 vrot.ToBytes(objectData, 52);
5156// data.Acceleration.ToBytes(objectData, 40); 5338 data.AngularVelocity.ToBytes(objectData, 64);
5157 rotation.ToBytes(objectData, 52);
5158 //data.AngularVelocity.ToBytes(objectData, 64);
5159 5339
5160 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5340 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
5161 5341
@@ -5168,7 +5348,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5168 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + 5348 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
5169 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); 5349 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
5170 update.ObjectData = objectData; 5350 update.ObjectData = objectData;
5171 update.ParentID = parentID; 5351
5352 SceneObjectPart parentPart = data.ParentPart;
5353 if (parentPart != null)
5354 update.ParentID = parentPart.ParentGroup.LocalId;
5355 else
5356 update.ParentID = 0;
5357
5172 update.PathCurve = 16; 5358 update.PathCurve = 16;
5173 update.PathScaleX = 100; 5359 update.PathScaleX = 100;
5174 update.PathScaleY = 100; 5360 update.PathScaleY = 100;
@@ -5205,15 +5391,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5205 data.RelativePosition.ToBytes(objectData, 0); 5391 data.RelativePosition.ToBytes(objectData, 0);
5206 data.Velocity.ToBytes(objectData, 12); 5392 data.Velocity.ToBytes(objectData, 12);
5207 data.Acceleration.ToBytes(objectData, 24); 5393 data.Acceleration.ToBytes(objectData, 24);
5208 try 5394
5209 { 5395 Quaternion rotation = data.RotationOffset;
5210 data.RotationOffset.ToBytes(objectData, 36); 5396 rotation.Normalize();
5211 } 5397 Vector3 vrot = new Vector3(rotation.X, rotation.Y, rotation.Z);
5212 catch (Exception e) 5398 vrot.ToBytes(objectData, 36);
5213 {
5214 m_log.Warn("[LLClientView]: exception converting quaternion to bytes, using Quaternion.Identity. Exception: " + e.ToString());
5215 OpenMetaverse.Quaternion.Identity.ToBytes(objectData, 36);
5216 }
5217 data.AngularVelocity.ToBytes(objectData, 48); 5399 data.AngularVelocity.ToBytes(objectData, 48);
5218 5400
5219 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5401 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
@@ -5387,7 +5569,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5387 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); 5569 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject);
5388 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); 5570 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject);
5389 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); 5571 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand);
5390 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply); 5572 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false);
5391 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); 5573 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest);
5392 AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance); 5574 AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance);
5393 AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing); 5575 AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing);
@@ -5448,8 +5630,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5448 AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); 5630 AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false);
5449 AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); 5631 AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false);
5450 AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); 5632 AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false);
5451 AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage); 5633 AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false);
5452 AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest); 5634 AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false);
5453 AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); 5635 AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest);
5454 AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); 5636 AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer);
5455 AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); 5637 AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket);
@@ -5481,7 +5663,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5481 AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); 5663 AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel);
5482 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); 5664 AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest);
5483 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); 5665 AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false);
5484 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest); 5666 AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest, false);
5485 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); 5667 AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest);
5486 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); 5668 AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false);
5487 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); 5669 AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false);
@@ -5594,82 +5776,146 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5594 5776
5595 #region Packet Handlers 5777 #region Packet Handlers
5596 5778
5779 public int TotalAgentUpdates { get; set; }
5780
5597 #region Scene/Avatar 5781 #region Scene/Avatar
5598 5782
5599 private bool HandleAgentUpdate(IClientAPI sener, Packet packet) 5783 // Threshold for body rotation to be a significant agent update
5784 // use the abs of cos
5785 private const float QDELTABody = 1.0f - 0.0001f;
5786 private const float QDELTAHead = 1.0f - 0.0001f;
5787 // Threshold for camera rotation to be a significant agent update
5788 private const float VDELTA = 0.01f;
5789
5790 /// <summary>
5791 /// This checks the update significance against the last update made.
5792 /// </summary>
5793 /// <remarks>Can only be called by one thread at a time</remarks>
5794 /// <returns></returns>
5795 /// <param name='x'></param>
5796 public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5600 { 5797 {
5601 if (OnAgentUpdate != null) 5798 return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x);
5799 }
5800
5801 /// <summary>
5802 /// This checks the movement/state update significance against the last update made.
5803 /// </summary>
5804 /// <remarks>Can only be called by one thread at a time</remarks>
5805 /// <returns></returns>
5806 /// <param name='x'></param>
5807 private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5808 {
5809 float qdelta1 = Math.Abs(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation));
5810 //qdelta2 = Math.Abs(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation));
5811
5812 bool movementSignificant =
5813 (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed
5814 || (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands
5815 || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed
5816 || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed
5817 || (qdelta1 < QDELTABody) // significant if body rotation above(below cos) threshold
5818 // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack
5819 // || (qdelta2 < QDELTAHead) // significant if head rotation above(below cos) threshold
5820 || (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed
5821 ;
5822 //if (movementSignificant)
5823 //{
5824 //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}",
5825 // qdelta1, qdelta2);
5826 //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}",
5827 // x.ControlFlags, x.Flags, x.Far, x.State);
5828 //}
5829 return movementSignificant;
5830 }
5831
5832 /// <summary>
5833 /// This checks the camera update significance against the last update made.
5834 /// </summary>
5835 /// <remarks>Can only be called by one thread at a time</remarks>
5836 /// <returns></returns>
5837 /// <param name='x'></param>
5838 private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5839 {
5840 float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis);
5841 float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter);
5842 float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis);
5843 float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis);
5844
5845 bool cameraSignificant =
5846 (vdelta1 > VDELTA) ||
5847 (vdelta2 > VDELTA) ||
5848 (vdelta3 > VDELTA) ||
5849 (vdelta4 > VDELTA)
5850 ;
5851
5852 //if (cameraSignificant)
5853 //{
5854 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}",
5855 // x.CameraAtAxis, x.CameraCenter);
5856 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}",
5857 // x.CameraLeftAxis, x.CameraUpAxis);
5858 //}
5859
5860 return cameraSignificant;
5861 }
5862
5863 private bool HandleAgentUpdate(IClientAPI sender, Packet packet)
5864 {
5865 // We got here, which means that something in agent update was significant
5866
5867 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5868 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
5869
5870 if (x.AgentID != AgentId || x.SessionID != SessionId)
5602 { 5871 {
5603 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; 5872 PacketPool.Instance.ReturnPacket(packet);
5873 return false;
5874 }
5604 5875
5605 #region Packet Session and User Check 5876 TotalAgentUpdates++;
5606 if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId)
5607 {
5608 PacketPool.Instance.ReturnPacket(packet);
5609 return false;
5610 }
5611 #endregion
5612 5877
5613 bool update = false; 5878 bool movement = CheckAgentMovementUpdateSignificance(x);
5614 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; 5879 bool camera = CheckAgentCameraUpdateSignificance(x);
5615
5616 if (m_lastAgentUpdateArgs != null)
5617 {
5618 // These should be ordered from most-likely to
5619 // least likely to change. I've made an initial
5620 // guess at that.
5621 update =
5622 (
5623 (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) ||
5624 (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) ||
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 5880
5644 if (update) 5881 // Was there a significant movement/state change?
5645 { 5882 if (movement)
5646// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); 5883 {
5884 m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation;
5885 m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags;
5886 m_thisAgentUpdateArgs.Far = x.Far;
5887 m_thisAgentUpdateArgs.Flags = x.Flags;
5888 m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation;
5889// m_thisAgentUpdateArgs.SessionID = x.SessionID;
5890 m_thisAgentUpdateArgs.State = x.State;
5647 5891
5648 m_lastAgentUpdateArgs.AgentID = x.AgentID; 5892 UpdateAgent handlerAgentUpdate = OnAgentUpdate;
5649 m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; 5893 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
5650 m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
5651 m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter;
5652 m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
5653 m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
5654 m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags;
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 5894
5661 UpdateAgent handlerAgentUpdate = OnAgentUpdate; 5895 if (handlerPreAgentUpdate != null)
5662 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; 5896 OnPreAgentUpdate(this, m_thisAgentUpdateArgs);
5663 5897
5664 if (handlerPreAgentUpdate != null) 5898 if (handlerAgentUpdate != null)
5665 OnPreAgentUpdate(this, m_lastAgentUpdateArgs); 5899 OnAgentUpdate(this, m_thisAgentUpdateArgs);
5666 5900
5667 if (handlerAgentUpdate != null) 5901 handlerAgentUpdate = null;
5668 OnAgentUpdate(this, m_lastAgentUpdateArgs); 5902 handlerPreAgentUpdate = null;
5903 }
5669 5904
5670 handlerAgentUpdate = null; 5905 // Was there a significant camera(s) change?
5671 handlerPreAgentUpdate = null; 5906 if (camera)
5672 } 5907 {
5908 m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
5909 m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter;
5910 m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
5911 m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
5912
5913 UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate;
5914
5915 if (handlerAgentCameraUpdate != null)
5916 handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs);
5917
5918 handlerAgentCameraUpdate = null;
5673 } 5919 }
5674 5920
5675 PacketPool.Instance.ReturnPacket(packet); 5921 PacketPool.Instance.ReturnPacket(packet);
@@ -6260,6 +6506,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6260 //m_log.Info("[LAND]: LAND:" + modify.ToString()); 6506 //m_log.Info("[LAND]: LAND:" + modify.ToString());
6261 if (modify.ParcelData.Length > 0) 6507 if (modify.ParcelData.Length > 0)
6262 { 6508 {
6509 // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore,
6510 // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit.
6511 m_justEditedTerrain = true; // Prevent terrain packet (Land layer) from being queued, make it unreliable
6263 if (OnModifyTerrain != null) 6512 if (OnModifyTerrain != null)
6264 { 6513 {
6265 for (int i = 0; i < modify.ParcelData.Length; i++) 6514 for (int i = 0; i < modify.ParcelData.Length; i++)
@@ -6275,6 +6524,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6275 } 6524 }
6276 } 6525 }
6277 } 6526 }
6527 m_justEditedTerrain = false; // Queue terrain packet (Land layer) if necessary, make it reliable again
6278 } 6528 }
6279 6529
6280 return true; 6530 return true;
@@ -6343,7 +6593,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6343 6593
6344 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length]; 6594 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length];
6345 for (int i=0; i<appear.WearableData.Length;i++) 6595 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)}; 6596 cacheitems[i] = new WearableCacheItem(){
6597 CacheId = appear.WearableData[i].CacheID,
6598 TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)
6599 };
6347 6600
6348 6601
6349 6602
@@ -6549,8 +6802,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6549 return true; 6802 return true;
6550 } 6803 }
6551 6804
6552 private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack) 6805 private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack)
6553 { 6806 {
6807 m_log.DebugFormat("[LLClientView] HandleCompleteAgentMovement");
6808
6554 Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion; 6809 Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion;
6555 if (handlerCompleteMovementToRegion != null) 6810 if (handlerCompleteMovementToRegion != null)
6556 { 6811 {
@@ -6636,6 +6891,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6636 } 6891 }
6637 #endregion 6892 #endregion
6638 6893
6894 if (SceneAgent.IsChildAgent)
6895 {
6896 SendCantSitBecauseChildAgentResponse();
6897 return true;
6898 }
6899
6639 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; 6900 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit;
6640 6901
6641 if (handlerAgentRequestSit != null) 6902 if (handlerAgentRequestSit != null)
@@ -6660,6 +6921,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6660 } 6921 }
6661 #endregion 6922 #endregion
6662 6923
6924 if (SceneAgent.IsChildAgent)
6925 {
6926 SendCantSitBecauseChildAgentResponse();
6927 return true;
6928 }
6929
6663 AgentSit handlerAgentSit = OnAgentSit; 6930 AgentSit handlerAgentSit = OnAgentSit;
6664 if (handlerAgentSit != null) 6931 if (handlerAgentSit != null)
6665 { 6932 {
@@ -6669,6 +6936,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6669 return true; 6936 return true;
6670 } 6937 }
6671 6938
6939 /// <summary>
6940 /// Used when a child agent gets a sit response which should not be fulfilled.
6941 /// </summary>
6942 private void SendCantSitBecauseChildAgentResponse()
6943 {
6944 SendAlertMessage("Try moving closer. Can't sit on object because it is not in the same region as you.");
6945 }
6946
6672 private bool HandleSoundTrigger(IClientAPI sender, Packet Pack) 6947 private bool HandleSoundTrigger(IClientAPI sender, Packet Pack)
6673 { 6948 {
6674 SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack; 6949 SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack;
@@ -7879,129 +8154,145 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7879 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); 8154 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request");
7880 8155
7881 TransferRequestPacket transfer = (TransferRequestPacket)Pack; 8156 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; 8157 UUID taskID = UUID.Zero;
7887 if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) 8158 if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem)
7888 { 8159 {
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())) 8160 if (!(((Scene)m_scene).Permissions.BypassPermissions()))
7898 { 8161 {
7899 if (taskID != UUID.Zero) // Prim 8162 // We're spawning a thread because the permissions check can block this thread
8163 Util.FireAndForget(delegate
7900 { 8164 {
7901 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); 8165 // This requests the asset if needed
8166 HandleSimInventoryTransferRequestWithPermsCheck(sender, transfer);
8167 });
8168 return true;
8169 }
8170 }
8171 else if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate)
8172 {
8173 //TransferRequestPacket does not include covenant uuid?
8174 //get scene covenant uuid
8175 taskID = m_scene.RegionInfo.RegionSettings.Covenant;
8176 }
7902 8177
7903 if (part == null) 8178 // This is non-blocking
7904 { 8179 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 8180
7911 TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); 8181 return true;
7912 if (tii == null) 8182 }
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 8183
7920 if (tii.Type == (int)AssetType.LSLText) 8184 private void HandleSimInventoryTransferRequestWithPermsCheck(IClientAPI sender, TransferRequestPacket transfer)
7921 { 8185 {
7922 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) 8186 UUID taskID = new UUID(transfer.TransferInfo.Params, 48);
7923 return true; 8187 UUID itemID = new UUID(transfer.TransferInfo.Params, 64);
7924 } 8188 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 8189
7942 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) 8190 //m_log.DebugFormat(
7943 { 8191 // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}",
7944 m_log.WarnFormat( 8192 // 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 8193
7950 if (tii.OwnerID != AgentId) 8194 //m_log.Debug("Transfer Request: " + transfer.ToString());
7951 { 8195 // Validate inventory transfers
7952 m_log.WarnFormat( 8196 // 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}", 8197 //
7954 Name, requestID, itemID, taskID, tii.OwnerID); 8198 if (taskID != UUID.Zero) // Prim
7955 return true; 8199 {
7956 } 8200 SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID);
7957 8201
7958 if (( 8202 if (part == null)
7959 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) 8203 {
7960 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) 8204 m_log.WarnFormat(
7961 { 8205 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist",
7962 m_log.WarnFormat( 8206 Name, requestID, itemID, taskID);
7963 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", 8207 return;
7964 Name, requestID, itemID, taskID); 8208 }
7965 return true;
7966 }
7967 8209
7968 if (tii.AssetID != requestID) 8210 TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID);
7969 { 8211 if (tii == null)
7970 m_log.WarnFormat( 8212 {
7971 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", 8213 m_log.WarnFormat(
7972 Name, requestID, itemID, taskID, tii.AssetID); 8214 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist",
7973 return true; 8215 Name, requestID, itemID, taskID);
7974 } 8216 return;
7975 } 8217 }
8218
8219 if (tii.Type == (int)AssetType.LSLText)
8220 {
8221 if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId))
8222 return;
8223 }
8224 else if (tii.Type == (int)AssetType.Notecard)
8225 {
8226 if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId))
8227 return;
8228 }
8229 else
8230 {
8231 // TODO: Change this code to allow items other than notecards and scripts to be successfully
8232 // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule
8233 if (part.OwnerID != AgentId)
8234 {
8235 m_log.WarnFormat(
8236 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}",
8237 Name, requestID, itemID, taskID, part.OwnerID);
8238 return;
7976 } 8239 }
7977 else // Agent 8240
8241 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0)
7978 { 8242 {
7979 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); 8243 m_log.WarnFormat(
7980 if (invAccess != null) 8244 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set",
7981 { 8245 Name, requestID, itemID, taskID);
7982 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID)) 8246 return;
7983 return false; 8247 }
7984 } 8248
7985 else 8249 if (tii.OwnerID != AgentId)
7986 { 8250 {
7987 return false; 8251 m_log.WarnFormat(
7988 } 8252 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}",
8253 Name, requestID, itemID, taskID, tii.OwnerID);
8254 return;
8255 }
8256
8257 if ((
8258 tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8259 != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer))
8260 {
8261 m_log.WarnFormat(
8262 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer",
8263 Name, requestID, itemID, taskID);
8264 return;
8265 }
8266
8267 if (tii.AssetID != requestID)
8268 {
8269 m_log.WarnFormat(
8270 "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}",
8271 Name, requestID, itemID, taskID, tii.AssetID);
8272 return;
7989 } 8273 }
7990 } 8274 }
7991 } 8275 }
7992 else 8276 else // Agent
7993 if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate) 8277 {
8278 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
8279 if (invAccess != null)
7994 { 8280 {
7995 //TransferRequestPacket does not include covenant uuid? 8281 if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID))
7996 //get scene covenant uuid 8282 return;
7997 taskID = m_scene.RegionInfo.RegionSettings.Covenant;
7998 } 8283 }
8284 else
8285 {
8286 return;
8287 }
8288 }
7999 8289
8290 // Permissions out of the way, let's request the asset
8000 MakeAssetRequest(transfer, taskID); 8291 MakeAssetRequest(transfer, taskID);
8001 8292
8002 return true;
8003 } 8293 }
8004 8294
8295
8005 private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack) 8296 private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack)
8006 { 8297 {
8007 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; 8298 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack;
@@ -11732,8 +12023,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11732 } 12023 }
11733 12024
11734 /// <summary> 12025 /// <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> 12026 /// </summary>
11738 /// <remarks> 12027 /// <remarks>
11739 /// At the moment, we always reply that there is no cached texture. 12028 /// At the moment, we always reply that there is no cached texture.
@@ -11741,6 +12030,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11741 /// <param name="simclient"></param> 12030 /// <param name="simclient"></param>
11742 /// <param name="packet"></param> 12031 /// <param name="packet"></param>
11743 /// <returns></returns> 12032 /// <returns></returns>
12033 // TODO: Convert old handler to use new method
12034 /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
12035 {
12036 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
12037
12038 if (cachedtex.AgentData.SessionID != SessionId)
12039 return false;
12040
12041
12042 List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>();
12043
12044 for (int i = 0; i < cachedtex.WearableData.Length; i++)
12045 {
12046 CachedTextureRequestArg arg = new CachedTextureRequestArg();
12047 arg.BakedTextureIndex = cachedtex.WearableData[i].TextureIndex;
12048 arg.WearableHashID = cachedtex.WearableData[i].ID;
12049
12050 requestArgs.Add(arg);
12051 }
12052
12053 CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest;
12054 if (handlerCachedTextureRequest != null)
12055 {
12056 handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs);
12057 }
12058
12059 return true;
12060 }*/
12061
11744 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) 12062 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11745 { 12063 {
11746 //m_log.Debug("texture cached: " + packet.ToString()); 12064 //m_log.Debug("texture cached: " + packet.ToString());
@@ -11749,156 +12067,105 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11749 12067
11750 if (cachedtex.AgentData.SessionID != SessionId) 12068 if (cachedtex.AgentData.SessionID != SessionId)
11751 return false; 12069 return false;
11752
11753 12070
11754 // TODO: don't create new blocks if recycling an old packet 12071 // TODO: don't create new blocks if recycling an old packet
11755 cachedresp.AgentData.AgentID = AgentId; 12072 cachedresp.AgentData.AgentID = AgentId;
11756 cachedresp.AgentData.SessionID = m_sessionId; 12073 cachedresp.AgentData.SessionID = m_sessionId;
11757 cachedresp.AgentData.SerialNum = m_cachedTextureSerial; 12074 cachedresp.AgentData.SerialNum = cachedtex.AgentData.SerialNum;
11758 m_cachedTextureSerial++;
11759 cachedresp.WearableData = 12075 cachedresp.WearableData =
11760 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length]; 12076 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
11761 12077
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; 12078 int maxWearablesLoop = cachedtex.WearableData.Length;
11770 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES) 12079 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES)
11771 maxWearablesLoop = AvatarWearable.MAX_WEARABLES; 12080 maxWearablesLoop = AvatarWearable.MAX_WEARABLES;
11772 12081
11773 if (bakedTextureModule != null && cache != null) 12082 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 12083
11777 WearableCacheItem[] cacheItems = null; 12084 // 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 12085
11789 /* 12086 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 12087
11815 if (cache != null && cacheItems != null) 12088 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 12089
12090 if (p != null && p.Appearance != null)
12091 {
12092 cacheItems = p.Appearance.WearableCacheItems;
12093 }
11826 12094
11827 } 12095 if (cacheItems != null)
11828 } 12096 {
11829 12097 for (int i = 0; i < maxWearablesLoop; i++)
11830 if (cacheItems != null)
11831 { 12098 {
11832 12099 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 12100
11838 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); 12101 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11839 cachedresp.WearableData[i].TextureIndex= cachedtex.WearableData[i].TextureIndex; 12102 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11840 cachedresp.WearableData[i].HostName = new byte[0]; 12103 cachedresp.WearableData[i].HostName = new byte[0];
11841 if (item != null && cachedtex.WearableData[i].ID == item.CacheId) 12104 if (cachedtex.WearableData[i].ID == cacheItems[idx].CacheId)
11842 { 12105 {
11843 12106 cachedresp.WearableData[i].TextureID = cacheItems[idx].TextureID;
11844 cachedresp.WearableData[i].TextureID = item.TextureID; 12107 cacheHits++;
11845 }
11846 else
11847 {
11848 cachedresp.WearableData[i].TextureID = UUID.Zero;
11849 }
11850 } 12108 }
11851 } 12109 else
11852 else
11853 {
11854 for (int i = 0; i < maxWearablesLoop; i++)
11855 { 12110 {
11856 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11857 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11858 cachedresp.WearableData[i].TextureID = UUID.Zero; 12111 cachedresp.WearableData[i].TextureID = UUID.Zero;
11859 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11860 cachedresp.WearableData[i].HostName = new byte[0];
11861 } 12112 }
11862 } 12113 }
11863 } 12114 }
11864 else 12115 else
11865 { 12116 {
11866 if (cache == null) 12117 for (int i = 0; i < maxWearablesLoop; i++)
11867 { 12118 {
11868 for (int i = 0; i < maxWearablesLoop; i++) 12119 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11869 { 12120 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11870 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); 12121 cachedresp.WearableData[i].TextureID = UUID.Zero;
11871 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; 12122 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11872 cachedresp.WearableData[i].TextureID = UUID.Zero; 12123 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 } 12124 }
11877 else 12125 }
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 12126
12127 m_log.DebugFormat("texture cached: hits {0}", cacheHits);
11885 12128
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; 12129 cachedresp.Header.Zerocoded = true;
11897 OutPacket(cachedresp, ThrottleOutPacketType.Task); 12130 OutPacket(cachedresp, ThrottleOutPacketType.Task);
11898 12131
11899 return true; 12132 return true;
11900 } 12133 }
11901 12134
12135 /// <summary>
12136 /// Send a response back to a client when it asks the asset server (via the region server) if it has
12137 /// its appearance texture cached.
12138 /// </summary>
12139 /// <param name="avatar"></param>
12140 /// <param name="serial"></param>
12141 /// <param name="cachedTextures"></param>
12142 /// <returns></returns>
12143 public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures)
12144 {
12145 ScenePresence presence = avatar as ScenePresence;
12146 if (presence == null)
12147 return;
12148
12149 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
12150
12151 // TODO: don't create new blocks if recycling an old packet
12152 cachedresp.AgentData.AgentID = m_agentId;
12153 cachedresp.AgentData.SessionID = m_sessionId;
12154 cachedresp.AgentData.SerialNum = serial;
12155 cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cachedTextures.Count];
12156
12157 for (int i = 0; i < cachedTextures.Count; i++)
12158 {
12159 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
12160 cachedresp.WearableData[i].TextureIndex = (byte)cachedTextures[i].BakedTextureIndex;
12161 cachedresp.WearableData[i].TextureID = cachedTextures[i].BakedTextureID;
12162 cachedresp.WearableData[i].HostName = new byte[0];
12163 }
12164
12165 cachedresp.Header.Zerocoded = true;
12166 OutPacket(cachedresp, ThrottleOutPacketType.Task);
12167 }
12168
11902 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) 12169 protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet)
11903 { 12170 {
11904 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; 12171 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet;
@@ -11924,8 +12191,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11924 if (part == null) 12191 if (part == null)
11925 { 12192 {
11926 // It's a ghost! tell the client to delete it from view. 12193 // It's a ghost! tell the client to delete it from view.
11927 simClient.SendKillObject(Scene.RegionInfo.RegionHandle, 12194 simClient.SendKillObject(new List<uint> { localId });
11928 new List<uint> { localId });
11929 } 12195 }
11930 else 12196 else
11931 { 12197 {
@@ -12299,6 +12565,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12299 12565
12300 shape.PCode = addPacket.ObjectData.PCode; 12566 shape.PCode = addPacket.ObjectData.PCode;
12301 shape.State = addPacket.ObjectData.State; 12567 shape.State = addPacket.ObjectData.State;
12568 shape.LastAttachPoint = addPacket.ObjectData.State;
12302 shape.PathBegin = addPacket.ObjectData.PathBegin; 12569 shape.PathBegin = addPacket.ObjectData.PathBegin;
12303 shape.PathEnd = addPacket.ObjectData.PathEnd; 12570 shape.PathEnd = addPacket.ObjectData.PathEnd;
12304 shape.PathScaleX = addPacket.ObjectData.PathScaleX; 12571 shape.PathScaleX = addPacket.ObjectData.PathScaleX;
@@ -12329,7 +12596,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12329 ClientInfo info = m_udpClient.GetClientInfo(); 12596 ClientInfo info = m_udpClient.GetClientInfo();
12330 12597
12331 info.proxyEP = null; 12598 info.proxyEP = null;
12332 info.agentcircuit = RequestClientInfo(); 12599 if (info.agentcircuit == null)
12600 info.agentcircuit = RequestClientInfo();
12333 12601
12334 return info; 12602 return info;
12335 } 12603 }
@@ -12712,11 +12980,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12712 OutPacket(dialog, ThrottleOutPacketType.Task); 12980 OutPacket(dialog, ThrottleOutPacketType.Task);
12713 } 12981 }
12714 12982
12715 public void StopFlying(ISceneEntity p) 12983 public void SendAgentTerseUpdate(ISceneEntity p)
12716 { 12984 {
12717 if (p is ScenePresence) 12985 if (p is ScenePresence)
12718 { 12986 {
12719 ScenePresence presence = p as ScenePresence; 12987// m_log.DebugFormat(
12988// "[LLCLIENTVIEW]: Immediately sending terse agent update for {0} to {1} in {2}",
12989// p.Name, Name, Scene.Name);
12990
12720 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities 12991 // 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 12992 // 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 12993 // velocity, collision plane and avatar height
@@ -12724,34 +12995,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 12995 // 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 12996 // when the avatar stands up
12726 12997
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 = 12998 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block =
12749 CreateImprovedTerseBlock(p, false); 12999 CreateImprovedTerseBlock(p, false);
12750 13000
12751 const float TIME_DILATION = 1.0f; 13001 const float TIME_DILATION = 1.0f;
12752 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); 13002 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
12753 13003
12754
12755 ImprovedTerseObjectUpdatePacket packet 13004 ImprovedTerseObjectUpdatePacket packet
12756 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( 13005 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
12757 PacketType.ImprovedTerseObjectUpdate); 13006 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..fe31bd9 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -31,6 +31,7 @@ using System.Net;
31using System.Threading; 31using System.Threading;
32using log4net; 32using log4net;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Monitoring;
34using OpenMetaverse; 35using OpenMetaverse;
35using OpenMetaverse.Packets; 36using OpenMetaverse.Packets;
36 37
@@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
81 /// hooked to put more data on the empty queue</summary> 82 /// hooked to put more data on the empty queue</summary>
82 public event QueueEmpty OnQueueEmpty; 83 public event QueueEmpty OnQueueEmpty;
83 84
85 public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates;
86
84 /// <summary>AgentID for this client</summary> 87 /// <summary>AgentID for this client</summary>
85 public readonly UUID AgentID; 88 public readonly UUID AgentID;
86 /// <summary>The remote address of the connected client</summary> 89 /// <summary>The remote address of the connected client</summary>
@@ -160,6 +163,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
160 private int m_maxRTO = 60000; 163 private int m_maxRTO = 60000;
161 public bool m_deliverPackets = true; 164 public bool m_deliverPackets = true;
162 165
166 public int m_lastStartpingTimeMS;
167 public int m_pingMS;
168
169 public int PingTimeMS
170 {
171 get
172 {
173 if (m_pingMS < 10)
174 return 10;
175 if(m_pingMS > 2000)
176 return 2000;
177 return m_pingMS;
178 }
179 }
180
181 /// <summary>
182 /// This is the percentage of the udp texture queue to add to the task queue since
183 /// textures are now generally handled through http.
184 /// </summary>
185 private double m_cannibalrate = 0.0;
186
187 private ClientInfo m_info = new ClientInfo();
188
163 /// <summary> 189 /// <summary>
164 /// Default constructor 190 /// Default constructor
165 /// </summary> 191 /// </summary>
@@ -197,6 +223,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
197 // Create an array of token buckets for this clients different throttle categories 223 // Create an array of token buckets for this clients different throttle categories
198 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; 224 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
199 225
226 m_cannibalrate = rates.CannibalizeTextureRate;
227
200 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) 228 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
201 { 229 {
202 ThrottleOutPacketType type = (ThrottleOutPacketType)i; 230 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
@@ -212,6 +240,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
212 240
213 // Initialize this to a sane value to prevent early disconnects 241 // Initialize this to a sane value to prevent early disconnects
214 TickLastPacketReceived = Environment.TickCount & Int32.MaxValue; 242 TickLastPacketReceived = Environment.TickCount & Int32.MaxValue;
243 m_pingMS = (int)(3.0 * server.TickCountResolution); // so filter doesnt start at 0;
215 } 244 }
216 245
217 /// <summary> 246 /// <summary>
@@ -241,20 +270,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
241 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists 270 // 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 271 // of pending and needed ACKs for every client every time some method wants information about
243 // this connection is a recipe for poor performance 272 // this connection is a recipe for poor performance
244 ClientInfo info = new ClientInfo(); 273
245 info.pendingAcks = new Dictionary<uint, uint>(); 274 m_info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
246 info.needAck = new Dictionary<uint, byte[]>(); 275 m_info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
247 276 m_info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
248 info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; 277 m_info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
249 info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; 278 m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
250 info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; 279 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
251 info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; 280 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
252 info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; 281 m_info.totalThrottle = (int)m_throttleCategory.DripRate;
253 info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; 282
254 info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; 283 return m_info;
255 info.totalThrottle = (int)m_throttleCategory.DripRate;
256
257 return info;
258 } 284 }
259 285
260 /// <summary> 286 /// <summary>
@@ -348,6 +374,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
348 texture = Math.Max(texture, LLUDPServer.MTU); 374 texture = Math.Max(texture, LLUDPServer.MTU);
349 asset = Math.Max(asset, LLUDPServer.MTU); 375 asset = Math.Max(asset, LLUDPServer.MTU);
350 376
377 // Since most textures are now delivered through http, make it possible
378 // to cannibalize some of the bw from the texture throttle to use for
379 // the task queue (e.g. object updates)
380 task = task + (int)(m_cannibalrate * texture);
381 texture = (int)((1 - m_cannibalrate) * texture);
382
351 //int total = resend + land + wind + cloud + task + texture + asset; 383 //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}", 384 //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); 385 // AgentID, resend, land, wind, cloud, task, texture, asset, total);
@@ -646,15 +678,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
646 /// <param name="categories">Throttle categories to fire the callback for</param> 678 /// <param name="categories">Throttle categories to fire the callback for</param>
647 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) 679 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
648 { 680 {
649 if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) 681// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
682 if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
650 { 683 {
684 m_isQueueEmptyRunning = true;
685
686 int start = Environment.TickCount & Int32.MaxValue;
687 const int MIN_CALLBACK_MS = 30;
688
689 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
690 if (m_nextOnQueueEmpty == 0)
691 m_nextOnQueueEmpty = 1;
692
651 // Use a value of 0 to signal that FireQueueEmpty is running 693 // Use a value of 0 to signal that FireQueueEmpty is running
652 m_nextOnQueueEmpty = 0; 694// m_nextOnQueueEmpty = 0;
653 // Asynchronously run the callback 695
654 Util.FireAndForget(FireQueueEmpty, categories); 696 m_categories = categories;
697
698 if (HasUpdates(m_categories))
699 {
700 // Asynchronously run the callback
701 Util.FireAndForget(FireQueueEmpty, categories);
702 }
703 else
704 {
705 m_isQueueEmptyRunning = false;
706 }
655 } 707 }
656 } 708 }
657 709
710 private bool m_isQueueEmptyRunning;
711 private ThrottleOutPacketTypeFlags m_categories = 0;
712
658 /// <summary> 713 /// <summary>
659 /// Fires the OnQueueEmpty callback and sets the minimum time that it 714 /// Fires the OnQueueEmpty callback and sets the minimum time that it
660 /// can be called again 715 /// can be called again
@@ -664,22 +719,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
664 /// signature</param> 719 /// signature</param>
665 private void FireQueueEmpty(object o) 720 private void FireQueueEmpty(object o)
666 { 721 {
667 const int MIN_CALLBACK_MS = 30; 722// int start = Environment.TickCount & Int32.MaxValue;
723// const int MIN_CALLBACK_MS = 30;
668 724
669 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; 725// if (m_udpServer.IsRunningOutbound)
670 QueueEmpty callback = OnQueueEmpty; 726// {
671 727 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
672 int start = Environment.TickCount & Int32.MaxValue; 728 QueueEmpty callback = OnQueueEmpty;
673 729
674 if (callback != null) 730 if (callback != null)
675 { 731 {
676 try { callback(categories); } 732// if (m_udpServer.IsRunningOutbound)
677 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } 733// {
678 } 734 try { callback(categories); }
735 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
736// }
737 }
738// }
739
740// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
741// if (m_nextOnQueueEmpty == 0)
742// m_nextOnQueueEmpty = 1;
743
744// }
679 745
680 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; 746 m_isQueueEmptyRunning = false;
681 if (m_nextOnQueueEmpty == 0)
682 m_nextOnQueueEmpty = 1;
683 } 747 }
684 internal void ForceThrottleSetting(int throttle, int setting) 748 internal void ForceThrottleSetting(int throttle, int setting)
685 { 749 {
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 4154ef2..3b0312d 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;
@@ -183,7 +293,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
183 /// <summary>Flag to signal when clients should send pings</summary> 293 /// <summary>Flag to signal when clients should send pings</summary>
184 protected bool m_sendPing; 294 protected bool m_sendPing;
185 295
296 private int m_animationSequenceNumber;
297
298 public int NextAnimationSequenceNumber
299 {
300 get
301 {
302 m_animationSequenceNumber++;
303 if (m_animationSequenceNumber > 2147482624)
304 m_animationSequenceNumber = 1;
305 return m_animationSequenceNumber;
306 }
307 }
308
309
310
186 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); 311 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
312
313 /// <summary>
314 /// Event used to signal when queued packets are available for sending.
315 /// </summary>
316 /// <remarks>
317 /// This allows the outbound loop to only operate when there is data to send rather than continuously polling.
318 /// Some data is sent immediately and not queued. That data would not trigger this event.
319 /// WRONG use. May be usefull in future revision
320 /// </remarks>
321// private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
322
187 private Pool<IncomingPacket> m_incomingPacketPool; 323 private Pool<IncomingPacket> m_incomingPacketPool;
188 324
189 /// <summary> 325 /// <summary>
@@ -204,7 +340,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
204 340
205 public Socket Server { get { return null; } } 341 public Socket Server { get { return null; } }
206 342
207 private int m_malformedCount = 0; // Guard against a spamming attack 343 /// <summary>
344 /// Record how many packets have been resent
345 /// </summary>
346 internal int PacketsResentCount { get; set; }
347
348 /// <summary>
349 /// Record how many packets have been sent
350 /// </summary>
351 internal int PacketsSentCount { get; set; }
352
353 /// <summary>
354 /// Record how many incoming packets are indicated as resends by clients.
355 /// </summary>
356 internal int IncomingPacketsResentCount { get; set; }
357
358 /// <summary>
359 /// Record how many inbound packets could not be recognized as LLUDP packets.
360 /// </summary>
361 public int IncomingMalformedPacketCount { get; private set; }
362
363 /// <summary>
364 /// Record how many inbound packets could not be associated with a simulator circuit.
365 /// </summary>
366 public int IncomingOrphanedPacketCount { get; private set; }
208 367
209 /// <summary> 368 /// <summary>
210 /// Record current outgoing client for monitoring purposes. 369 /// Record current outgoing client for monitoring purposes.
@@ -225,16 +384,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
225 384
226 // Measure the resolution of Environment.TickCount 385 // Measure the resolution of Environment.TickCount
227 TickCountResolution = 0f; 386 TickCountResolution = 0f;
228 for (int i = 0; i < 5; i++) 387 for (int i = 0; i < 10; i++)
229 { 388 {
230 int start = Environment.TickCount; 389 int start = Environment.TickCount;
231 int now = start; 390 int now = start;
232 while (now == start) 391 while (now == start)
233 now = Environment.TickCount; 392 now = Environment.TickCount;
234 TickCountResolution += (float)(now - start) * 0.2f; 393 TickCountResolution += (float)(now - start) * 0.1f;
235 } 394 }
236 m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms");
237 TickCountResolution = (float)Math.Ceiling(TickCountResolution); 395 TickCountResolution = (float)Math.Ceiling(TickCountResolution);
396 m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms");
238 397
239 #endregion Environment.TickCount Measurement 398 #endregion Environment.TickCount Measurement
240 399
@@ -242,6 +401,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
242 int sceneThrottleBps = 0; 401 int sceneThrottleBps = 0;
243 bool usePools = false; 402 bool usePools = false;
244 403
404
405
245 IConfig config = configSource.Configs["ClientStack.LindenUDP"]; 406 IConfig config = configSource.Configs["ClientStack.LindenUDP"];
246 if (config != null) 407 if (config != null)
247 { 408 {
@@ -291,6 +452,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
291 m_throttle = new TokenBucket(null, sceneThrottleBps); 452 m_throttle = new TokenBucket(null, sceneThrottleBps);
292 ThrottleRates = new ThrottleRates(configSource); 453 ThrottleRates = new ThrottleRates(configSource);
293 454
455 Random rnd = new Random(Util.EnvironmentTickCount());
456 m_animationSequenceNumber = rnd.Next(11474826);
457
294 if (usePools) 458 if (usePools)
295 EnablePools(); 459 EnablePools();
296 } 460 }
@@ -461,6 +625,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
461 m_scene = (Scene)scene; 625 m_scene = (Scene)scene;
462 m_location = new Location(m_scene.RegionInfo.RegionHandle); 626 m_location = new Location(m_scene.RegionInfo.RegionHandle);
463 627
628 StatsManager.RegisterStat(
629 new Stat(
630 "InboxPacketsCount",
631 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
632 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
633 "",
634 "clientstack",
635 scene.Name,
636 StatType.Pull,
637 MeasuresOfInterest.AverageChangeOverTime,
638 stat => stat.Value = packetInbox.Count,
639 StatVerbosity.Debug));
640
464 // XXX: These stats are also pool stats but we register them separately since they are currently not 641 // 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() 642 // turned on and off by EnablePools()/DisablePools()
466 StatsManager.RegisterStat( 643 StatsManager.RegisterStat(
@@ -521,6 +698,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
521 EnablePoolStats(); 698 EnablePoolStats();
522 699
523 MainConsole.Instance.Commands.AddCommand( 700 MainConsole.Instance.Commands.AddCommand(
701 "Debug", false, "debug lludp packet",
702 "debug lludp packet [--default] <level> [<avatar-first-name> <avatar-last-name>]",
703 "Turn on packet debugging",
704 "If level > 255 then all incoming and outgoing packets are logged.\n"
705 + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n"
706 + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n"
707 + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n"
708 + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n"
709 + "If level <= 0 then no packets are logged.\n"
710 + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n"
711 + "In this case, you cannot also specify an avatar name.\n"
712 + "If an avatar name is given then only packets from that avatar are logged.",
713 HandlePacketCommand);
714
715 MainConsole.Instance.Commands.AddCommand(
524 "Debug", 716 "Debug",
525 false, 717 false,
526 "debug lludp start", 718 "debug lludp start",
@@ -559,10 +751,79 @@ namespace OpenSim.Region.ClientStack.LindenUDP
559 "debug lludp status", 751 "debug lludp status",
560 "Return status of LLUDP packet processing.", 752 "Return status of LLUDP packet processing.",
561 HandleStatusCommand); 753 HandleStatusCommand);
754/* disabled
755 MainConsole.Instance.Commands.AddCommand(
756 "Debug",
757 false,
758 "debug lludp toggle agentupdate",
759 "debug lludp toggle agentupdate",
760 "Toggle whether agentupdate packets are processed or simply discarded.",
761 HandleAgentUpdateCommand);
762 */
763 }
764
765 private void HandlePacketCommand(string module, string[] args)
766 {
767 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
768 return;
769
770 bool setAsDefaultLevel = false;
771 OptionSet optionSet = new OptionSet().Add("default", o => setAsDefaultLevel = o != null);
772 List<string> filteredArgs = optionSet.Parse(args);
773
774 string name = null;
775
776 if (filteredArgs.Count == 6)
777 {
778 if (!setAsDefaultLevel)
779 {
780 name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]);
781 }
782 else
783 {
784 MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default logging level");
785 return;
786 }
787 }
788
789 if (filteredArgs.Count > 3)
790 {
791 int newDebug;
792 if (int.TryParse(filteredArgs[3], out newDebug))
793 {
794 if (setAsDefaultLevel)
795 {
796 DefaultClientPacketDebugLevel = newDebug;
797 MainConsole.Instance.OutputFormat(
798 "Debug packet debug for new clients set to {0} in {1}", DefaultClientPacketDebugLevel, m_scene.Name);
799 }
800 else
801 {
802 m_scene.ForEachScenePresence(sp =>
803 {
804 if (name == null || sp.Name == name)
805 {
806 MainConsole.Instance.OutputFormat(
807 "Packet debug for {0} ({1}) set to {2} in {3}",
808 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name);
809
810 sp.ControllingClient.DebugPacketLevel = newDebug;
811 }
812 });
813 }
814 }
815 else
816 {
817 MainConsole.Instance.Output("Usage: debug lludp packet [--default] 0..255 [<first-name> <last-name>]");
818 }
819 }
562 } 820 }
563 821
564 private void HandleStartCommand(string module, string[] args) 822 private void HandleStartCommand(string module, string[] args)
565 { 823 {
824 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
825 return;
826
566 if (args.Length != 4) 827 if (args.Length != 4)
567 { 828 {
568 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); 829 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
@@ -580,6 +841,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
580 841
581 private void HandleStopCommand(string module, string[] args) 842 private void HandleStopCommand(string module, string[] args)
582 { 843 {
844 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
845 return;
846
583 if (args.Length != 4) 847 if (args.Length != 4)
584 { 848 {
585 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); 849 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
@@ -597,6 +861,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
597 861
598 private void HandlePoolCommand(string module, string[] args) 862 private void HandlePoolCommand(string module, string[] args)
599 { 863 {
864 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
865 return;
866
600 if (args.Length != 4) 867 if (args.Length != 4)
601 { 868 {
602 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); 869 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
@@ -627,8 +894,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
627 } 894 }
628 } 895 }
629 896
897 bool m_discardAgentUpdates;
898
899 private void HandleAgentUpdateCommand(string module, string[] args)
900 {
901 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
902 return;
903
904 m_discardAgentUpdates = !m_discardAgentUpdates;
905
906 MainConsole.Instance.OutputFormat(
907 "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name);
908 }
909
630 private void HandleStatusCommand(string module, string[] args) 910 private void HandleStatusCommand(string module, string[] args)
631 { 911 {
912 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
913 return;
914
632 MainConsole.Instance.OutputFormat( 915 MainConsole.Instance.OutputFormat(
633 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); 916 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled");
634 917
@@ -636,6 +919,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
636 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); 919 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
637 920
638 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); 921 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off");
922
923 MainConsole.Instance.OutputFormat(
924 "Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel);
639 } 925 }
640 926
641 public bool HandlesRegion(Location x) 927 public bool HandlesRegion(Location x)
@@ -643,44 +929,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP
643 return x == m_location; 929 return x == m_location;
644 } 930 }
645 931
646 public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) 932// public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
647 { 933// {
648 // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way 934// // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way
649 if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting) 935// if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting)
650 allowSplitting = false; 936// allowSplitting = false;
651 937//
652 if (allowSplitting && packet.HasVariableBlocks) 938// if (allowSplitting && packet.HasVariableBlocks)
653 { 939// {
654 byte[][] datas = packet.ToBytesMultiple(); 940// byte[][] datas = packet.ToBytesMultiple();
655 int packetCount = datas.Length; 941// int packetCount = datas.Length;
656 942//
657 if (packetCount < 1) 943// if (packetCount < 1)
658 m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length); 944// m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length);
659 945//
660 for (int i = 0; i < packetCount; i++) 946// for (int i = 0; i < packetCount; i++)
661 { 947// {
662 byte[] data = datas[i]; 948// byte[] data = datas[i];
663 m_scene.ForEachClient( 949// m_scene.ForEachClient(
664 delegate(IClientAPI client) 950// delegate(IClientAPI client)
665 { 951// {
666 if (client is LLClientView) 952// if (client is LLClientView)
667 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); 953// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
668 } 954// }
669 ); 955// );
670 } 956// }
671 } 957// }
672 else 958// else
673 { 959// {
674 byte[] data = packet.ToBytes(); 960// byte[] data = packet.ToBytes();
675 m_scene.ForEachClient( 961// m_scene.ForEachClient(
676 delegate(IClientAPI client) 962// delegate(IClientAPI client)
677 { 963// {
678 if (client is LLClientView) 964// if (client is LLClientView)
679 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); 965// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
680 } 966// }
681 ); 967// );
682 } 968// }
683 } 969// }
684 970
685 /// <summary> 971 /// <summary>
686 /// Start the process of sending a packet to the client. 972 /// Start the process of sending a packet to the client.
@@ -700,6 +986,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
700 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) 986 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
701 allowSplitting = false; 987 allowSplitting = false;
702 988
989 bool packetQueued = false;
990
703 if (allowSplitting && packet.HasVariableBlocks) 991 if (allowSplitting && packet.HasVariableBlocks)
704 { 992 {
705 byte[][] datas = packet.ToBytesMultiple(); 993 byte[][] datas = packet.ToBytesMultiple();
@@ -711,16 +999,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
711 for (int i = 0; i < packetCount; i++) 999 for (int i = 0; i < packetCount; i++)
712 { 1000 {
713 byte[] data = datas[i]; 1001 byte[] data = datas[i];
714 SendPacketData(udpClient, data, packet.Type, category, method); 1002
1003 if (!SendPacketData(udpClient, data, packet.Type, category, method))
1004 packetQueued = true;
715 } 1005 }
716 } 1006 }
717 else 1007 else
718 { 1008 {
719 byte[] data = packet.ToBytes(); 1009 byte[] data = packet.ToBytes();
720 SendPacketData(udpClient, data, packet.Type, category, method); 1010 packetQueued = SendPacketData(udpClient, data, packet.Type, category, method);
721 } 1011 }
722 1012
723 PacketPool.Instance.ReturnPacket(packet); 1013 PacketPool.Instance.ReturnPacket(packet);
1014
1015 /// WRONG use. May be usefull in future revision
1016// if (packetQueued)
1017// m_dataPresentEvent.Set();
724 } 1018 }
725 1019
726 /// <summary> 1020 /// <summary>
@@ -734,7 +1028,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 1028 /// 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. 1029 /// resend of the packet is done.
736 /// </param> 1030 /// </param>
737 public void SendPacketData( 1031 /// <returns>true if the data was sent immediately, false if it was queued for sending</returns>
1032 public bool SendPacketData(
738 LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method) 1033 LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
739 { 1034 {
740 int dataLength = data.Length; 1035 int dataLength = data.Length;
@@ -807,7 +1102,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
807 // packet so that it isn't sent before a queued update packet. 1102 // packet so that it isn't sent before a queued update packet.
808 bool requestQueue = type == PacketType.KillObject; 1103 bool requestQueue = type == PacketType.KillObject;
809 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority)) 1104 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority))
1105 {
810 SendPacketFinal(outgoingPacket); 1106 SendPacketFinal(outgoingPacket);
1107 return true;
1108 }
1109
1110 return false;
811 1111
812 #endregion Queue or Send 1112 #endregion Queue or Send
813 } 1113 }
@@ -848,6 +1148,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
848 pc.PingID.OldestUnacked = 0; 1148 pc.PingID.OldestUnacked = 0;
849 1149
850 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null); 1150 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null);
1151 udpClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount();
851 } 1152 }
852 1153
853 public void CompletePing(LLUDPClient udpClient, byte pingID) 1154 public void CompletePing(LLUDPClient udpClient, byte pingID)
@@ -883,7 +1184,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 1184 // 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. 1185 // 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. 1186 // This is the same as processing as the async process of a logout request.
886 Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); 1187 Util.FireAndForget(o => DeactivateClientDueToTimeout(client, timeoutTicks));
887 1188
888 return; 1189 return;
889 } 1190 }
@@ -988,6 +1289,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
988 else 1289 else
989 { 1290 {
990 Interlocked.Increment(ref udpClient.PacketsResent); 1291 Interlocked.Increment(ref udpClient.PacketsResent);
1292
1293 // We're not going to worry about interlock yet since its not currently critical that this total count
1294 // is 100% correct
1295 PacketsResentCount++;
991 } 1296 }
992 1297
993 #endregion Sequence Number Assignment 1298 #endregion Sequence Number Assignment
@@ -995,6 +1300,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
995 // Stats tracking 1300 // Stats tracking
996 Interlocked.Increment(ref udpClient.PacketsSent); 1301 Interlocked.Increment(ref udpClient.PacketsSent);
997 1302
1303 // We're not going to worry about interlock yet since its not currently critical that this total count
1304 // is 100% correct
1305 PacketsSentCount++;
1306
998 // Put the UDP payload on the wire 1307 // Put the UDP payload on the wire
999 AsyncBeginSend(buffer); 1308 AsyncBeginSend(buffer);
1000 1309
@@ -1002,6 +1311,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1002 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; 1311 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
1003 } 1312 }
1004 1313
1314 private void RecordMalformedInboundPacket(IPEndPoint endPoint)
1315 {
1316// if (m_malformedCount < 100)
1317// m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1318
1319 IncomingMalformedPacketCount++;
1320
1321 if ((IncomingMalformedPacketCount % 10000) == 0)
1322 m_log.WarnFormat(
1323 "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}",
1324 IncomingMalformedPacketCount, endPoint);
1325 }
1326
1005 public override void PacketReceived(UDPPacketBuffer buffer) 1327 public override void PacketReceived(UDPPacketBuffer buffer)
1006 { 1328 {
1007 // Debugging/Profiling 1329 // Debugging/Profiling
@@ -1023,6 +1345,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1023// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", 1345// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
1024// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 1346// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1025 1347
1348 RecordMalformedInboundPacket(endPoint);
1349
1026 return; // Drop undersized packet 1350 return; // Drop undersized packet
1027 } 1351 }
1028 1352
@@ -1041,6 +1365,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1041// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", 1365// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}",
1042// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 1366// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1043 1367
1368 RecordMalformedInboundPacket(endPoint);
1369
1044 return; // Malformed header 1370 return; // Malformed header
1045 } 1371 }
1046 1372
@@ -1056,34 +1382,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1056 // Only allocate a buffer for zerodecoding if the packet is zerocoded 1382 // Only allocate a buffer for zerodecoding if the packet is zerocoded
1057 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 1383 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
1058 } 1384 }
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) 1385 catch (Exception e)
1071 { 1386 {
1072 if (m_malformedCount < 100) 1387 if (IncomingMalformedPacketCount < 100)
1073 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); 1388 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 } 1389 }
1080 1390
1081 // Fail-safe check 1391 // Fail-safe check
1082 if (packet == null) 1392 if (packet == null)
1083 { 1393 {
1084 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:", 1394 if (IncomingMalformedPacketCount < 100)
1085 buffer.DataLength, buffer.RemoteEndPoint); 1395 {
1086 m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); 1396 m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:",
1397 buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
1398 }
1399
1400 RecordMalformedInboundPacket(endPoint);
1401
1087 return; 1402 return;
1088 } 1403 }
1089 1404
@@ -1127,12 +1442,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1127 queue.Enqueue(buffer); 1442 queue.Enqueue(buffer);
1128 return; 1443 return;
1129 } 1444 }
1445
1446/*
1447 else if (packet.Type == PacketType.CompleteAgentMovement)
1448 {
1449 // Send ack straight away to let the viewer know that we got it.
1450 SendAckImmediate(endPoint, packet.Header.Sequence);
1451
1452 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1453 // buffer.
1454 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1455
1456 Util.FireAndForget(HandleCompleteMovementIntoRegion, array);
1457
1458 return;
1459 }
1460 */
1130 } 1461 }
1131 1462
1132 // Determine which agent this packet came from 1463 // Determine which agent this packet came from
1133 if (client == null || !(client is LLClientView)) 1464 if (client == null || !(client is LLClientView))
1134 { 1465 {
1135 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1466 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1467
1468 IncomingOrphanedPacketCount++;
1469
1470 if ((IncomingOrphanedPacketCount % 10000) == 0)
1471 m_log.WarnFormat(
1472 "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}",
1473 IncomingOrphanedPacketCount, endPoint);
1474
1136 return; 1475 return;
1137 } 1476 }
1138 1477
@@ -1211,6 +1550,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1211 1550
1212 #region Incoming Packet Accounting 1551 #region Incoming Packet Accounting
1213 1552
1553 // We're not going to worry about interlock yet since its not currently critical that this total count
1554 // is 100% correct
1555 if (packet.Header.Resent)
1556 IncomingPacketsResentCount++;
1557
1214 // Check the archive of received reliable packet IDs to see whether we already received this packet 1558 // 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)) 1559 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
1216 { 1560 {
@@ -1233,6 +1577,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1233 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); 1577 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
1234 #endregion BinaryStats 1578 #endregion BinaryStats
1235 1579
1580// AgentUpdate mess removed from here
1581
1236 #region Ping Check Handling 1582 #region Ping Check Handling
1237 1583
1238 if (packet.Type == PacketType.StartPingCheck) 1584 if (packet.Type == PacketType.StartPingCheck)
@@ -1242,7 +1588,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1242 // We don't need to do anything else with ping checks 1588 // We don't need to do anything else with ping checks
1243 StartPingCheckPacket startPing = (StartPingCheckPacket)packet; 1589 StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
1244 CompletePing(udpClient, startPing.PingID.PingID); 1590 CompletePing(udpClient, startPing.PingID.PingID);
1245 1591
1246 if ((Environment.TickCount - m_elapsedMSSinceLastStatReport) >= 3000) 1592 if ((Environment.TickCount - m_elapsedMSSinceLastStatReport) >= 3000)
1247 { 1593 {
1248 udpClient.SendPacketStats(); 1594 udpClient.SendPacketStats();
@@ -1252,7 +1598,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1252 } 1598 }
1253 else if (packet.Type == PacketType.CompletePingCheck) 1599 else if (packet.Type == PacketType.CompletePingCheck)
1254 { 1600 {
1255 // We don't currently track client ping times 1601 int t = Util.EnvironmentTickCountSubtract(udpClient.m_lastStartpingTimeMS);
1602 int c = udpClient.m_pingMS;
1603 c = 800 * c + 200 * t;
1604 c /= 1000;
1605 udpClient.m_pingMS = c;
1256 return; 1606 return;
1257 } 1607 }
1258 1608
@@ -1272,11 +1622,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1272 incomingPacket = new IncomingPacket((LLClientView)client, packet); 1622 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1273 } 1623 }
1274 1624
1275 if (incomingPacket.Packet.Type == PacketType.AgentUpdate || 1625// if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
1276 incomingPacket.Packet.Type == PacketType.ChatFromViewer) 1626// incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1627 if (incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1277 packetInbox.EnqueueHigh(incomingPacket); 1628 packetInbox.EnqueueHigh(incomingPacket);
1278 else 1629 else
1279 packetInbox.EnqueueLow(incomingPacket); 1630 packetInbox.EnqueueLow(incomingPacket);
1631
1280 } 1632 }
1281 1633
1282 #region BinaryStats 1634 #region BinaryStats
@@ -1393,7 +1745,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1393 1745
1394 try 1746 try
1395 { 1747 {
1396 // DateTime startTime = DateTime.Now; 1748// DateTime startTime = DateTime.Now;
1397 object[] array = (object[])o; 1749 object[] array = (object[])o;
1398 endPoint = (IPEndPoint)array[0]; 1750 endPoint = (IPEndPoint)array[0];
1399 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; 1751 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
@@ -1413,20 +1765,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1413 uccp.CircuitCode.SessionID, 1765 uccp.CircuitCode.SessionID,
1414 endPoint, 1766 endPoint,
1415 sessionInfo); 1767 sessionInfo);
1416
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 1768
1426 // Now we know we can handle more data 1769 // Now we know we can handle more data
1427 Thread.Sleep(200); 1770 Thread.Sleep(200);
1428 1771
1429 // Obtain the queue and remove it from the cache 1772 // Obtain the pending queue and remove it from the cache
1430 Queue<UDPPacketBuffer> queue = null; 1773 Queue<UDPPacketBuffer> queue = null;
1431 1774
1432 lock (m_pendingCache) 1775 lock (m_pendingCache)
@@ -1435,6 +1778,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1435 { 1778 {
1436 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); 1779 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1437 return; 1780 return;
1781
1438 } 1782 }
1439 m_pendingCache.Remove(endPoint); 1783 m_pendingCache.Remove(endPoint);
1440 } 1784 }
@@ -1442,12 +1786,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1442 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); 1786 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
1443 1787
1444 // Reinject queued packets 1788 // Reinject queued packets
1445 while(queue.Count > 0) 1789 while (queue.Count > 0)
1446 { 1790 {
1447 UDPPacketBuffer buf = queue.Dequeue(); 1791 UDPPacketBuffer buf = queue.Dequeue();
1448 PacketReceived(buf); 1792 PacketReceived(buf);
1449 } 1793 }
1794
1450 queue = null; 1795 queue = null;
1796
1797 // Send ack straight away to let the viewer know that the connection is active.
1798 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
1799 // circuit code to the existing child agent. This is not particularly obvious.
1800 SendAckImmediate(endPoint, uccp.Header.Sequence);
1801
1802 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1803 if (client != null)
1804 {
1805 AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1806 bool tp = (aCircuit.teleportFlags > 0);
1807 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from
1808 if (!tp)
1809 client.SceneAgent.SendInitialDataToMe();
1810 }
1451 } 1811 }
1452 else 1812 else
1453 { 1813 {
@@ -1457,8 +1817,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1457 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); 1817 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1458 lock (m_pendingCache) 1818 lock (m_pendingCache)
1459 m_pendingCache.Remove(endPoint); 1819 m_pendingCache.Remove(endPoint);
1460 } 1820 }
1461
1462 // m_log.DebugFormat( 1821 // m_log.DebugFormat(
1463 // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms", 1822 // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms",
1464 // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds); 1823 // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds);
@@ -1475,6 +1834,117 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1475 e.StackTrace); 1834 e.StackTrace);
1476 } 1835 }
1477 } 1836 }
1837/*
1838 private void HandleCompleteMovementIntoRegion(object o)
1839 {
1840 IPEndPoint endPoint = null;
1841 IClientAPI client = null;
1842
1843 try
1844 {
1845 object[] array = (object[])o;
1846 endPoint = (IPEndPoint)array[0];
1847 CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1];
1848
1849 m_log.DebugFormat(
1850 "[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, m_scene.Name);
1851
1852 // Determine which agent this packet came from
1853 // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination
1854 // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode
1855 // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these
1856 // packets asynchronously, we need to account for this thread proceeding more quickly than the
1857 // UseCircuitCode thread.
1858 int count = 40;
1859 while (count-- > 0)
1860 {
1861 if (m_scene.TryGetClient(endPoint, out client))
1862 {
1863 if (!client.IsActive)
1864 {
1865 // This check exists to catch a condition where the client has been closed by another thread
1866 // but has not yet been removed from the client manager (and possibly a new connection has
1867 // not yet been established).
1868 m_log.DebugFormat(
1869 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.",
1870 endPoint, client.Name, m_scene.Name);
1871 }
1872 else if (client.SceneAgent == null)
1873 {
1874 // This check exists to catch a condition where the new client has been added to the client
1875 // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too
1876 // eager, then the new ScenePresence may not have registered a listener for this messsage
1877 // before we try to process it.
1878 // XXX: A better long term fix may be to add the SceneAgent before the client is added to
1879 // the client manager
1880 m_log.DebugFormat(
1881 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.",
1882 endPoint, client.Name, m_scene.Name);
1883 }
1884 else
1885 {
1886 break;
1887 }
1888 }
1889 else
1890 {
1891 m_log.DebugFormat(
1892 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.",
1893 endPoint, m_scene.Name);
1894 }
1895
1896 Thread.Sleep(200);
1897 }
1898
1899 if (client == null)
1900 {
1901 m_log.DebugFormat(
1902 "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.",
1903 endPoint, m_scene.Name);
1904
1905 return;
1906 }
1907 else if (!client.IsActive || client.SceneAgent == null)
1908 {
1909 // This check exists to catch a condition where the client has been closed by another thread
1910 // but has not yet been removed from the client manager.
1911 // The packet could be simply ignored but it is useful to know if this condition occurred for other debugging
1912 // purposes.
1913 m_log.DebugFormat(
1914 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.",
1915 endPoint, client.Name, m_scene.Name);
1916
1917 return;
1918 }
1919
1920 IncomingPacket incomingPacket1;
1921
1922 // Inbox insertion
1923 if (UsePools)
1924 {
1925 incomingPacket1 = m_incomingPacketPool.GetObject();
1926 incomingPacket1.Client = (LLClientView)client;
1927 incomingPacket1.Packet = packet;
1928 }
1929 else
1930 {
1931 incomingPacket1 = new IncomingPacket((LLClientView)client, packet);
1932 }
1933
1934 packetInbox.Enqueue(incomingPacket1);
1935 }
1936 catch (Exception e)
1937 {
1938 m_log.ErrorFormat(
1939 "[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1940 endPoint != null ? endPoint.ToString() : "n/a",
1941 client != null ? client.Name : "unknown",
1942 client != null ? client.AgentId.ToString() : "unknown",
1943 e.Message,
1944 e.StackTrace);
1945 }
1946 }
1947*/
1478 1948
1479 /// <summary> 1949 /// <summary>
1480 /// Send an ack immediately to the given endpoint. 1950 /// Send an ack immediately to the given endpoint.
@@ -1544,6 +2014,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1544 2014
1545 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 2015 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1546 client.OnLogout += LogoutHandler; 2016 client.OnLogout += LogoutHandler;
2017 client.DebugPacketLevel = DefaultClientPacketDebugLevel;
1547 2018
1548 ((LLClientView)client).DisableFacelights = m_disableFacelights; 2019 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1549 2020
@@ -1562,21 +2033,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1562 /// regular client pings. 2033 /// regular client pings.
1563 /// </remarks> 2034 /// </remarks>
1564 /// <param name='client'></param> 2035 /// <param name='client'></param>
1565 private void DeactivateClientDueToTimeout(LLClientView client) 2036 /// <param name='timeoutTicks'></param>
2037 private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks)
1566 { 2038 {
1567 lock (client.CloseSyncLock) 2039 lock (client.CloseSyncLock)
1568 { 2040 {
2041 ClientLogoutsDueToNoReceives++;
2042
1569 m_log.WarnFormat( 2043 m_log.WarnFormat(
1570 "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", 2044 "[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); 2045 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, m_scene.Name);
1572
1573 StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
1574 2046
1575 if (!client.SceneAgent.IsChildAgent) 2047 if (!client.SceneAgent.IsChildAgent)
1576 client.Kick("Simulator logged you out due to connection timeout"); 2048 client.Kick("Simulator logged you out due to connection timeout.");
1577
1578 client.CloseWithoutChecks(true);
1579 } 2049 }
2050
2051 m_scene.CloseAgent(client.AgentId, true);
1580 } 2052 }
1581 2053
1582 private void IncomingPacketHandler() 2054 private void IncomingPacketHandler()
@@ -1592,6 +2064,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1592 { 2064 {
1593 IncomingPacket incomingPacket = null; 2065 IncomingPacket incomingPacket = null;
1594 2066
2067 /*
1595 // HACK: This is a test to try and rate limit packet handling on Mono. 2068 // 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 2069 // If it works, a more elegant solution can be devised
1597 if (Util.FireAndForgetCount() < 2) 2070 if (Util.FireAndForgetCount() < 2)
@@ -1599,6 +2072,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1599 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); 2072 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping");
1600 Thread.Sleep(30); 2073 Thread.Sleep(30);
1601 } 2074 }
2075 */
1602 2076
1603 if (packetInbox.Dequeue(100, ref incomingPacket)) 2077 if (packetInbox.Dequeue(100, ref incomingPacket))
1604 { 2078 {
@@ -1608,7 +2082,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1608 m_incomingPacketPool.ReturnObject(incomingPacket); 2082 m_incomingPacketPool.ReturnObject(incomingPacket);
1609 } 2083 }
1610 } 2084 }
1611 catch (Exception ex) 2085 catch(Exception ex)
1612 { 2086 {
1613 m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex); 2087 m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex);
1614 } 2088 }
@@ -1694,9 +2168,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1694 2168
1695 // If nothing was sent, sleep for the minimum amount of time before a 2169 // If nothing was sent, sleep for the minimum amount of time before a
1696 // token bucket could get more tokens 2170 // token bucket could get more tokens
2171
1697 if (!m_packetSent) 2172 if (!m_packetSent)
1698 Thread.Sleep((int)TickCountResolution); 2173 Thread.Sleep((int)TickCountResolution);
1699 2174
2175 // .... wrong core code removed
2176
2177
1700 Watchdog.UpdateThread(); 2178 Watchdog.UpdateThread();
1701 } 2179 }
1702 catch (Exception ex) 2180 catch (Exception ex)
@@ -1912,7 +2390,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1912 if (!client.IsLoggingOut) 2390 if (!client.IsLoggingOut)
1913 { 2391 {
1914 client.IsLoggingOut = true; 2392 client.IsLoggingOut = true;
1915 client.Close(false, false); 2393 m_scene.CloseAgent(client.AgentId, false);
1916 } 2394 }
1917 } 2395 }
1918 } 2396 }
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 }